一下flatMap
1 KeyLog(3,"Entered Number 3").flatMap(a => KeyLog("Hello", "Entered String 'Hello'")) 2 //> res2: Exercises.keylog.KeyLog[String] = [Hello,Entered Number 3;Entered Stri 3 //| ng 'Hello']
最终log值:"Entered Number 3;Entered String 'Hello'。我们实现了在运算flatMap过程中对log进行的累积。
现在我们可以先获取KeyLog的Monad实例,然后进行flatMap串联及使用for-comprehension进行行令编程了:
1 object KeyLog { 2 def apply[K](k: K, msg: String): KeyLog[K] = new KeyLog[K] { 3 def value = k 4 def log = msg 5 } 6 import scalaz._ 7 import Scalaz._ 8 implicit object keylogMonad extends Monad[KeyLog] { 9 def point[K](k: => K): KeyLog[K] = KeyLog(k,"") 10 def bind[K,I](kk: KeyLog[K])(f: K => KeyLog[I]): KeyLog[I] = kk flatMap f 11 } 12 }
在KeyLog Monad实例里bind使用了我们设计的flatMap函数。看看flatMap串接和for-comprehension效果:
def enterInt(k: Int): KeyLog[Int] = KeyLog(k, "Number:"+k.toString) //> enterInt: (k: Int)Exercises.keylog.KeyLog[Int]
def enterStr(k: String): KeyLog[String] = KeyLog(k,"String:"+k) //> enterStr: (k: String)Exercises.keylog.KeyLog[String]
enterInt(3) >>= {a => enterInt(4) >>= {b => enterStr("Result:") map {c => c + (a * b).toString} }} //> res3: Exercises.keylog.KeyLog[String] = [Result:12,Number:3;Number:4;String: //| Result:;]
for { a <- enterInt(3) b <- enterInt(4) c <- enterStr("Result:") } yield c + (a * b).toString //> res4: Exercises.keylog.KeyLog[String] = [Result:12,Number:3;Number:4;String //| :Result:;]
value和log都按照要求实现了转变。
在使用for-comprehension时突然想到守卫函数(guard function)。我想既然已经得到了KeyLog的Monad实例,是不是可以在它的for-comprehension里使用守卫函数呢?就像这样:
1 for { 2 a <- enterInt(3) 3 b <- enterInt(4) if b > 0
4 c <- enterStr("Result:") 5 } yield c + (a * b).toString
不过无法通过编译。提示需要filter函数。查了一下MonadPlus typeclass可以提供这个函数。那么我们就沿着惯用的套路获取一下KeyLog的MonadPlus实例。MonadPlus trait的定义如下:scalaz/MonadPlus.scala
1 trait MonadPlus[F[_]] extends Monad[F] with ApplicativePlus[F] { self =>
2 ////
3
4 /** Remove `f`-failing `A`s in `fa`, by which we mean: in the 5 * expression `filter(filter(fa)(f))(g)`, `g` will never be invoked 6 * for any `a` where `f(a)` returns false. 7 */
8 def filter[A](fa: F[A])(f: A => Boolean) =
9 bind(fa)(a => if (f(a)) point(a) else empty[A]) 10 ...
MonadPlus又继承了ApplicativePlus:scalar/ApplicativePlus.scala
1 trait ApplicativePlus[F[_]] extends Applicative[F] with PlusEmpty[F] { self =>
ApplicativePlus又继承了PlusEmpty: scalaz/PlusEmpty.scala
1 trait PlusEmpty[F[_]] extends Plus[F] { self =>
2 ////
3 def empty[A]: F[A] 4 ...
PlusEmpty定义了抽象成员empty[A],又继承了Plus: scalar/Plus.scala
1 trait Plus[F[_]] { self =>
2 ////
3
4 /**The composition of Plus `F` and `G`, `[x]F[G[x]]`, is a Plus */
5 def compose[G[_]](implicit G0: Plus[G]): Plus[({type λ[α] = F[G[α]]})#λ] = new CompositionPlus[F, G] { 6 implicit def F = self 7
8 implicit def G = G0 9 } 10
11 /**The product of Plus `F` and `G`, `[x](F[x], G[x]])`, is a Plus */
12 def product[G[_]](implicit G0: Plus[G]): Plus[({type λ[α] = (F[α], G[α])})#λ] = new ProductPlus[F, G] { 13 implicit def F = self 14
15 implicit def G = G0 16 } 17
18 def plus[A](a: F[A], b: => F[A]): F[A] 19
20 def semigroup[A]: Semigroup[F[A]] = new Semigroup[F[A]] { 21 def append(f1: F[A], f2: => F[A]): F[A] = plus(f1, f2) 22 } 23 ...
Plus