2011年12月14日水曜日

Monad

朝、親に電車代を交渉し忘れて rpscala にいけないという・・・・・

今日はMonad。

Monad

Monadが何たるかは

モナドは象だ

を読みましょう!(まるなげ

モナドなんて高階関数を持ってて結合可能なコンテナぐらいの認識でいいのです!(ぼうろん

ここではScalazでMonadに関連する関数を紹介します。

Monadのインスタンスを直接定義するか、BindとPureのインスタンスが定義されていればimplicit parameterにMonadのインスタンスが供給されます。

case class ScalaChan[A](value: A)
implicit def ScalaChanEqual[A]: Equal[ScalaChan[A]] = equalA
implicit def ScalaChanShow[A]: Show[ScalaChan[A]] = showA
implicit lazy val ScalaChanPure: Pure[ScalaChan] = new Pure[ScalaChan] {
def pure[A](a: => A): ScalaChan[A] = ScalaChan(a)
}
implicit lazy val ScalaChanBind: Bind[ScalaChan] = new Bind[ScalaChan] {
def bind[A, B](a: ScalaChan[A], f: A => ScalaChan[B]): ScalaChan[B] = f(a.value)
}
def f[A[_]: Monad, B: Semigroup](a: A[B]) = for {
i <- a
j <- a
} yield i |+| j
f(100.some) assert_=== 200.some
f(ScalaChan("Scala")) assert_=== ScalaChan("ScalaScala")
implicit lazy val ScalaChanMonad: Monad[ScalaChan] = new Monad[ScalaChan] {
def pure[A](a: => A): ScalaChan[A] = ScalaChan(a)
def bind[A, B](a: ScalaChan[A], f: A => ScalaChan[B]): ScalaChan[B] = f(a.value)
}
view raw monad1.scala hosted with ❤ by GitHub

getOrElseM

値Mに包まれたOption[A]がSomeの場合、値を返し、Noneの場合呼び出し側を返します。

'Scalaz.wrapNel.getOrElseM('Scala.some.wrapNel) assert_=== NonEmptyList('Scala)
'Scalaz.wrapNel.getOrElseM(none.wrapNel) assert_=== NonEmptyList('Scalaz)
view raw monad2.scala hosted with ❤ by GitHub

ifM

trueの場合とfalseの場合で値を振り分けます。

true.some.ifM('Scalaz.some, 'Scala.some) assert_=== Option('Scalaz)
nel(false, true, false).ifM('イカちゃん.wrapNel, 'Scalaちゃん.wrapNel) assert_=== NonEmptyList('Scalaちゃん,'イカちゃん,'Scalaちゃん)
view raw monad3.scala hosted with ❤ by GitHub

replicateM

型パラメータを1つとる型と繰り返す回数を渡し、包まれた値を連結します。

'Z'.some.replicate[List](5) assert_=== List(Option('Z'), Option('Z'), Option('Z'), Option('Z'), Option('Z'))
'Z'.some.replicateM[List](3) assert_=== Option(List('Z', 'Z', 'Z'))
view raw monad4.scala hosted with ❤ by GitHub

foldLeftM, foldRightM

普通のfoldと違い、包まれた値を返す関数を渡します。

nel(1, 2, 3).foldLeftM(mzero[Int])(_ |+| _ |> (i => (i % 2 === 0).option(i)))
nel(1, 2, 3).foldLeftM(mzero[Int])(_.replicate[List](_)) assert_=== List(0, 0, 0, 0, 0, 0)
view raw monad5.scala hosted with ❤ by GitHub

Scalaではあるクラスを実装するのではなく、flatMapとmapさえ実装されていればfor式が使えちゃう。
for式はflatMapがネストしたら使えばいいんじゃなイカ?

0 件のコメント:

コメントを投稿