设为首页 加入收藏

TOP

Scalaz(10)- Monad:就是一种函数式编程模式-a design pattern(一)
2017-10-10 12:13:36 】 浏览:4667
Tags:Scalaz Monad 就是 函数 编程 模式 design pattern

    Monad typeclass不是一种类型,而是一种程序设计模式(design pattern),是泛函编程中最重要的编程概念,因而很多行内人把FP又称为Monadic Programming。这其中透露的Monad重要性则不言而喻。Scalaz是通过Monad typeclass为数据运算的程序提供了一套规范的编程方式,如常见的for-comprehension。而不同类型的Monad实例则会支持不同的程序运算行为,如:Option Monad在运算中如果遇到None值则会中途退出;State Monad会确保状态值会伴随着程序运行流程直到终结;List Monad运算可能会产生多个结果等等。Scalaz提供了很多不同种类的Monad如:StateMonad, IOMonad, ReaderMonad, WriterMonad,MonadTransformer等等,这从另一个角度也重申了Monad概念在泛函编程里的重要性。听起来以上这些描述好像有点摸不着头脑,可能应该把它们放在本篇最终总结,不过我还是想让大家有个大的概念。对下面的讨论细节的理解能有所帮助。我们还是从Monad trait开始介绍吧:

 1 trait Monad[F[_]] extends Applicative[F] with Bind[F] { self =>
 2   //// scalaz/Monad.scala
 3 
 4   override def map[A,B](fa: F[A])(f: A => B) = bind(fa)(a => point(f(a)))  5 ...  6 trait Applicative[F[_]] extends Apply[F] { self =>
 7   //// scalaz/Applicative.scala
 8   def point[A](a: => A): F[A]  9 ... 10 trait Apply[F[_]] extends Functor[F] { self =>
11   //// scalaz/Apply.scala
12   def ap[A,B](fa: => F[A])(f: => F[A => B]): F[B] 13 ... 14 trait Bind[F[_]] extends Apply[F] { self =>
15   //// scalaz/Bind.scala
16 
17   /** Equivalent to `join(map(fa)(f))`. */
18   def bind[A, B](fa: F[A])(f: A => F[B]): F[B] 19 
20   override def ap[A, B](fa: => F[A])(f: => F[A => B]): F[B] = { 21     lazy val fa0 = fa 22  bind(f)(map(fa0)) 23  } 24 ...

上面这些类型trait的继承关系是这样的:Monad继承了Applicative和Bind,Applicative继承了Apply, Apply继承了Functor, Bind也继承了Apply。所以Monad同时又是Applicative和Functor,因为Monad实现了map和ap函数。一个Monad实例可以调用所有Applicative和Functor提供的组件函数。任何实例只需要实现抽象函数point和bind就可以成为Monad实例,然后就可以使用Monad所有的组件函数了。

Monad所提供的主要注入方法(injected method)是在BindOps和MonadOps里。在BindOps里主要提供了flatMap: scalaz/syntax/BindSyntax.scala

 1 final class BindOps[F[_],A] private[syntax](val self: F[A])(implicit val F: Bind[F]) extends Ops[F[A]] {  2   ////
 3   import Liskov.<~<, Leibniz.===
 4 
 5   def flatMap[B](f: A => F[B]) = F.bind(self)(f)  6 
 7   def >>=[B](f: A => F[B]) = F.bind(self)(f)  8 
 9   def ?[B](f: A => F[B]) = F.bind(self)(f) 10 ...

主要是这个flatMap函数,在scalaz里用>>=来表示。这是一个大家都起码耳熟的函数:好像flatMap就代表了Monad。在MonadOps里提供的注入方法如下:scalaz/Syntax/MonadSyntax.scala

 1 final class MonadOps[F[_],A] private[syntax](val self: F[A])(implicit val F: Monad[F]) extends Ops[F[A]] {  2   ////
 3 
 4   def liftM[G[_[_], _]](implicit G: MonadTrans[G]): G[F, A] = G.liftM(self)  5 
 6   def whileM[G[_]](p: F[Boolean])(implicit G: MonadPlus[G]): F[G[A]] = F.whileM(p, self)  7 
 8   def whileM_(p: F[Boolean]): F[Unit] = F.whileM_(p, self)  9 
10   def untilM[G[_]](p: => F[Boolean])(implicit G: MonadPlus[G]): F[G[A]] = F.untilM(self, p) 11 
12   def untilM_(p: => F[Boolean]): F[Unit] = F.untilM_(self, p) 13 
14   def iterateWhile(p: A => Boolean): F[A] = F.iterateWhile(self)(p) 15 
16   def iterateUntil(p: A => Boolean): F[A] = F.iterateUntil(self)(p) 17 
18   ////
19 }

看起来这些注入方法都是一些编程语言里的流程控制语法(control flow syntax)。这是不是暗示着Monad最终会实现某种编程语言?我们把这些函数的使用方法放在后面的一些讨论去。我们先来分析一下flatMap函数,因为这是个Monad代表函数。下面是Functor,Applicative和Monad施用函数格式比较:

1 // Functor    :  map[A,B]    (F[A])(f:   A => B):  F[B]
2 // Applicative:  ap[A,B]     (F[A])(f: F[A => B]): F[B] 
3 // Monad      :  flatMap[A,B](F[A])(f: A => F[B]): F[B]

以上三种函数款式基本上是一致的。大家都说这就是三种FP的函数施用方式:在一个容器内进行函数的运算后把结果还留在容器内、得到的效果是这样的:F[A] => F[B]。只是它们分别用不同的方式提供这个施用的函数。Functor的map提供了普通函数,Applicative通过容器提供了施用函数ap而Monad则

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Scalaz(9)- typeclass:checki.. 下一篇Scalaz(11)- Monad:你存在的..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目