モナドはコンテナだ。リラックマもコンテナ(中身入ってるし)だ。
だったら、モナドはリラックマだ。
と言う訳で、リラックマでモナド則書いてみた。
まず、リラックマの実装。リラックマは、皮と中身がある。そもそもいない時もある。
まさにMaybeだ。なので、Optionにしてみる。
えぇ手抜きですとも。
package controllers | |
import play.api._ | |
import play.api.mvc._ | |
import play.api.cache._ | |
import play.api.Play.current | |
object EA { | |
case class Bind[a1,a2](x:Either[a1,a2]) { | |
def #>>[b](f:a2 => Either[a1,b]):Either[a1,b] = x.right flatMap f |
package controllers | |
import play.api._ | |
import play.api.mvc._ | |
import play.api.cache._ | |
import play.api.Play.current | |
object Application extends Controller { | |
import EA._ | |
def index(id:String) = EitherAction {req => |
scala> val l = Left(3) | |
l: Left[Int,Nothing] = Left(3) | |
scala> val r = Right(3) | |
r: Right[Nothing,Int] = Right(3) | |
scala> def calc = (x:Either[Int,Int]) => x.right.map(_ + 2).left.map(_ * 2).right.map(_ + 3) | |
culc: Either[Int,Int] => Product with Either[Int,Int] with Serializable | |
scala> calc(r) |
def f[a] = (d:List[Either[Throwable,a]]) => | |
d.collect{case Left(x) => x}.headOption.toLeft(d.map{case Right(x) => x}) | |
scala> Some(List(Right("4"),Right("3"))) map f | |
res11: Option[Product with Either[Throwable,List[java.lang.String]] with Serializable] = Some(Right(List(4, 3))) | |
scala> Some(List(Right("4"),Left(new RuntimeException),Right("3"))) map f | |
res12: Option[Product with Either[Throwable,List[java.lang.String]] with Serializable] = Some(Left(java.lang.RuntimeException)) | |
scala> Some(List(Right("4"),Left(new RuntimeException("a")),Right("3"),Left(new RuntimeException("b")))) map f |
package controllers | |
import play.api._ | |
import play.api.mvc._ | |
import EA._ | |
object Application extends Controller { | |
implicit def either2Bind(s:Either[String,Int]) = new Bind(s) | |
implicit def int2Bind(x:Int) = new Bind[String,Int](Right(x)) |
Caused by: java.lang.RuntimeException: cannot serialize an immutable.HashSet where all items have the same 32-bit hash code | |
at scala.sys.package$.error(package.scala:27) | |
at scala.collection.immutable.HashSet$HashSetCollision1.writeObject(HashSet.scala:168) | |
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) | |
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) | |
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) | |
at java.lang.reflect.Method.invoke(Method.java:601) |
def toDate[A:DateMagnet](x:A) = implicitly[DateMagnet[A]].convert(x) | |
trait DateMagnet[A]{ | |
type Result | |
def convert(x:A):Result | |
} | |
object DateMagnet { | |
implicit def fromInt = new DateMagnet[(Int, Int, Int)] { | |
type Result = java.util.Calendar |
/* | |
概要:入力されたCSVの契約種別コードに従って計算を行い、結果を出力する | |
仕様: | |
CSV入力パターン: [名前],[契約種別コード(A or B or C)],[基本料金],[使用量1段階],[使用量2段階] | |
※文字列はクォート無し | |
sample: "foo,A,3000,,","bar,B,1000,200,","foobar,C,1000,200,300" | |
契約種別コード別料金計算仕様: | |
A: 基本料金 | |
B: 基本料金 + 使用量1段階 * 0.1 | |
C: 基本料金 + 使用量1段階 * 0.02 + 使用量2段階 * 0.3 |
// ネタ元: | |
// 衝撃的なデータベース理論・関手的データモデル 入門 | |
// http://d.hatena.ne.jp/m-hiyama/20130211/1360577040 | |
//データ保持用 | |
object Strage { | |
trait Strage[A] { | |
def get: A | |
} | |
} |