2011年12月23日金曜日

Writer, WriterT

Identity, MA, MABで使う型クラスはほとんど書いたので、モナドを書いていこうと思います。

Writer

計算中の値とは別にもう1つログを作ります。

val result = for {
i <- 100.set("Hello")
j <- 100.set("World")
} yield i + j
result.value assert_=== ("HelloWorld", 200)
view raw writer1.scala hosted with ❤ by GitHub

値とログはoverとwrittenで取り出せます。

result.over assert_=== 200
result.written assert_=== "HelloWorld"
view raw writer2.scala hosted with ❤ by GitHub

Writers#writerで直接インスタンスを作ることも出来ます。

val result = for {
i <- writer("Scalaちゃん".wrapNel, 3)
j <- writer("イカちゃん".wrapNel, 4)
} yield i * j
result.value assert_=== (NonEmptyList("Scalaちゃん", "イカちゃん"), 12)
view raw writer3.scala hosted with ❤ by GitHub

WriterT

Writerのモナド変換子バージョン。

type ScalaChan[A] = WriterT[Option, String, A]
val result = for {
i <- "Scala".some.put("Hello"): ScalaChan[String]
j <- "Scalaz".some.putWith(_.shows.dual |+| "World".dual): ScalaChan[String]
} yield i |+| j
result.value assert_=== Some(("HelloWorldScalaz", "ScalaScalaz"))
view raw writert1.scala hosted with ❤ by GitHub

WriterTに定義してある型クラスのインスタンスは全て[α]WriterT[M, W, α]となっているので、BindやFunctorのインスタンスを利用するには、型の別名が必要みたいです。
put, putWithの他に、liftw, liftwWith, writerTがあります。

type Ikamusume[A] = WriterT[List, NonEmptyList[String], A]
val result = for {
i <- List("Scalaちゃん", "イカ娘").liftw[NonEmptyList].apply("Hello"): Ikamusume[String]
j <- List("Scala", "Scalaz").liftwWith[NonEmptyList].apply(_ |+| "World"): Ikamusume[String]
} yield i |+| j
result.value assert_=== List((NonEmptyList("Hello", "ScalaWorld"), "ScalaちゃんScala"), (NonEmptyList("Hello", "ScalazWorld"), "ScalaちゃんScalaz"), (NonEmptyList("Hello", "ScalaWorld"), "イカ娘Scala"), (NonEmptyList("Hello", "ScalazWorld"), "イカ娘Scalaz"))
((writerT(("Hello", 11).some): ScalaChan[Int]) >|> (writerT(("World", 13).some): ScalaChan[Int])).value assert_=== Some(("HelloWorld", 13))
view raw writert2.scala hosted with ❤ by GitHub

Writerは使えそうだけど使い方がわからないモナドの一つでしたが、モナド変換子の使い方もわかったし、これからはロジックの中に組み込んでいけそうです。

0 件のコメント:

コメントを投稿