设为首页 加入收藏

TOP

Scalaz(14)- Monad:函数组合-Kleisli to Reader(一)
2017-10-10 12:13:31 】 浏览:3357
Tags:Scalaz Monad 函数 组合 Kleisli Reader

  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](
首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Scalaz(13)- Monad:Writer - .. 下一篇Scalaz(15)- Monad:依赖注入..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目