Monad Reader就是一种函数的组合。在scalaz里函数(function)本身就是Monad,自然也就是Functor和applicative。我们可以用Monadic方法进行函数组合:
1 import scalaz._ 2 import Scalaz._ 3 object decompose { 4 //两个测试函数
5 val f = (_: Int) + 3 //> f : Int => Int = <function1>
6 val g = (_: Int) * 5 //> g : Int => Int = <function1> 7 //functor
8 val h = f map g // f andThen g //> h : Int => Int = <function1>
9 val h1 = g map f // f compose g //> h1 : Int => Int = <function1>
10 h(2) //g(f(2)) //> res0: Int = 25
11 h1(2) //f(g(2)) //> res1: Int = 13 12 //applicative
13 val k = (f |@| g){_ + _} //> k : Int => Int = <function1>
14 k(10) // f(10)+g(10) //> res2: Int = 63 15 //monad
16 val m = g.flatMap{a => f.map(b => a+b)} //> m : Int => Int = <function1>
17 val n = for { 18 a <- f 19 b <- g 20 } yield a + b //> n : Int => Int = <function1>
21 m(10) //> res3: Int = 63
22 n(10) //> res4: Int = 63
23 }
以上的函数f,g必须满足一定的条件才能实现组合。这个从f(g(2))或g(f(2))可以看出:必需固定有一个输入参数及输入参数类型和函数结果类型必需一致,因为一个函数的输出成为另一个函数的输入。在FP里这样的函数组合就是Monadic Reader。
但是FP里函数运算结果一般都是M[R]这样格式的,所以我们需要对f:A => M[B],g:B => M[C]这样的函数进行组合。这就是scalaz里的Kleisli了。Kleisli就是函数A=>M[B]的类封套,从Kleisli的类定义可以看出:scalaz/Kleisli.scala
1 final case class Kleisli[M[_], A, B](run: A => M[B]) { self =>
2 ... 3 trait KleisliFunctions { 4 /**Construct a Kleisli from a Function1 */
5 def kleisli[M[_], A, B](f: A => M[B]): Kleisli[M, A, B] = Kleisli(f) 6 ...
Kleisli的目的是把Monadic函数组合起来或者更形象说连接起来。Kleisli提供的操作方法如>=>可以这样理解:
(A=>M[B]) >=> (B=>M[C]) >=> (C=>M[D]) 最终运算结果M[D]
可以看出Kleisli函数组合有着固定的模式:
1、函数必需是 A => M[B]这种模式;只有一个输入,结果是一个Monad M[_]
2、上一个函数输出M[B],他的运算值B就是下一个函数的输入。这就要求下一个函数的输入参数类型必需是B
3、M必须是个Monad;这个可以从Kleisli的操作函数实现中看出:scalaz/Kleisli.scala
1 /** alias for `andThen` */
2 def >=>[C](k: Kleisli[M, B, C])(implicit b: Bind[M]): Kleisli[M, A, C] = kleisli((a: A) => b.bind(this(a))(k.run)) 3
4 def andThen[C](k: Kleisli[M, B, C])(implicit b: Bind[M]): Kleisli[M, A, C] = this >=> k 5
6 def >==>[C](k: B => M[C])(implicit b: Bind[M]): Kleisli[M, A, C] = this >=> kleisli(k) 7
8 def andThenK[C](k: B => M[C])(implicit b: Bind[M]): Kleisli[M, A, C] = this >==> k 9
10 /** alias for `compose` */
11 def <=<[C](k: Kleisli[M, C, A])(implicit b: Bind[M]): Kleisli[M, C, B] = k >=> this
12
13 def compose[C](k: Kleisli[M, C, A])(implicit b: Bind[M]): Kleisli[M, C, B] = k >=> this
14
15 def <==<[C](k: C => M[A])(implicit b: Bind[M]): Kleisli[M, C, B] = kleisli(k) >=> this
16
17 def composeK[C](k: C => M[A])(implicit b: Bind[M]): Kleisli[M, C, B] = this <==< k
拿操作函数>=>(andThen)举例:implicit b: Bind[M]明确了M必须是个Monad。
kleisli((a: A) => b.bind(this(a))(k.run))的意思是先运算M[A],接着再运算k,以M[A]运算结果值a作为下一个函数k.run的输入参数。整个实现过程并不复杂。
实际上Reader就是Kleisli的一个特殊案例:在这里kleisli的M[]变成了Id[],因为Id[A]=A >>> A=>Id[B] = A=>B,就是我们上面提到的Reader,我们看看Reader在scalaz里是如何定义的:scalar/package.scala
1 type ReaderT[F[_], E, A] = Kleisli[F, E, A] 2 val ReaderT = Kleisli 3 type =?>[E, A] = Kleisli[Option, E, A] 4 type Reader[E, A] = ReaderT[Id, E, A] 5
6 type Writer[W, A] = WriterT[Id, W, A] 7 type Unwriter[W, A] = UnwriterT[Id, W, A] 8
9 object Reader { 10 def apply[E, A](f: E => A): Reader[E, A] = Kleisli[Id, E, A](f) 11 } 12
13 object Writer { 14 def apply[W, A](