{{ message }}

Instantly share code, notes, and snippets.

Last active Aug 29, 2015
published tags
true
 ScaVaToScala Scala Scalaz Programming

##使用情境

Writer Monad在scalaz的source code裡的註解是`Computations that log a value` 假設今天有一個需求，是要進行一個有多個步驟的處理，而這個處理的過程我們需要Log起來，也就是在每個步驟加上對應的記錄，並且在處理完成之後，要能把過程印在畫面上，在許多個步驟在處理時，這些Log要怎麼收集呢？

`Writer`其實是`WriterT`的別名(alias)，並且指定WriterT中的第一個型態`scalaz.Id`是scalaz的Identity Monad

###Writer type Writer[W, A] = WriterT[Id, W, A]

``````object Writer {
def apply[W, A](w: W, a: A): WriterT[Id, W, A] = WriterT[Id, W, A]((w, a))
}
``````

WriterT這邊主要裡面有個`run`，他就是幫你把這兩個值(一個是你原本的值，另一個是你要寫的log)包在一起成tuple，然後放進Identity Monad，另外就是written和value了，分別是你所write的log，和本來要回傳的value。

###WriterT

``````sealed trait WriterT[F[+_], +W, +A] { self =>
val run: F[(W, A)]

def written(implicit F: Functor[F]): F[W] =
F.map(run)(_._1)
def value(implicit F: Functor[F]): F[A] =
F.map(run)(_._2)
}
``````

##舉個例子

1. 用名字查出User的Id

2. 用Id查這個User的State

3. 用Id再查User的Age

4. 最後做個Foo的Check

def searchUserId(name:String)=123.set(Vector(s"search user with name:[\$name] found id:[123]"))

def getState(id:Int)="alive".set(Vector("state is alive"))

def getAge(id:Int)=18.set(Vector("age is 18"))

def checkFoo(state:String,age:Int)=(age>=18)?"Old Foo".set(Vector(s"age older then 18 is Old Foo."))|"Young Foo".set(Vector(s"age younger than 18 is Young Foo."))

val foo = for{ uid <- searchUserId("Joe") state <- getState(uid) age <- getAge(uid) foo <- checkFoo(state,age) } yield foo foo: scalaz.WriterT[scalaz.Id.Id,scala.collection.immutable.Vector[String],String] = WriterT((Vector(search user with name:[Joe] found id:[123], state is alive, age is 18, age older then 18 is Old Foo.),Old Foo))

foo.value scalaz.Id.Id[String] = Old Foo

foo.written scalaz.Id.Id[scala.collection.immutable.Vector[String]] = Vector(search user with name:[Joe] found id:[123], state is alive, age is 18, age older then 18 is Old Foo.)

##有關效能的注意事項

Reference