Scalaz(25)- Monad: Monad Transformer-叠加Monad效果

  中间插播了几篇scalaz数据类型,今后又要回到Monad专题。因为FP的特征正是Monad式编制程序(Monadic
programming),所以必须尽量领会认识Monad、熟谙通晓Monad运用。曾经看到1段对Monad的叙述:“Monadic
for-comprehension正是壹种嵌入式编程语言,由它的Monad提供它的语法”。但假如每种Monad的for-comprehension都独立提供壹套语法的话,那种编制程序语言就展现煞是枯燥、功效不难了。那么既然是FP,我们理应能够经过函数组合(function
composition)来把无数简练的for-comprehension组合成1套完善的编制程序语言吧?比如那样:Option[A]
>>> IO[Option[A]] >>>
IO[Either[String,Option[A]]。恰恰,Monad是不协理函数组合的。先精晓一下函数组合:Functor是足以构成的,大家得以把fa和fb组合成2个更复杂的Functor
fab,大家来证Bellamy下:

高级中学档插播了几篇scalaz数据类型,今后又要回去Monad专题。因为FP的特征正是Monad式编程(Monadic
programming),所以必须尽量驾驭认识Monad、明白精通Monad运用。曾经看到一段对Monad的叙述:“Monadic
for-comprehension正是一种嵌入式编制程序语言,由它的Monad提供它的语法”。但即便每一种Monad的for-comprehension都独立提供1套语法的话,那种编制程序语言就呈现煞是单调、功用简单了。那么既然是FP,大家应有能够经过函数组合(function
composition)来把过多粗略的for-comprehension组合成一套完善的编制程序语言吧?比如那样:Option[A]
>>> IO[Option[A]] >>>
IO[Either[String,Option[A]]。恰恰,Monad是不帮忙函数组合的。先精通一下函数组合:Functor是能够整合的,大家能够把fa和fb组合成三个更扑朔迷离的Functor
fab,大家来说澳优(Ausnutria Hyproca)下:

 def composeFunctor[M[_],N[_]](fa: Functor[M], fb: Functor[N]): Functor[({type mn[x] = M[N[x]]})#mn] =
   new Functor[({type mn[x] = M[N[x]]})#mn] {
        def map[A,B](fab: M[N[A]])(f: A => B): M[N[B]] =
           fa.map(fab)(n => fb.map(n)(f))
   }                                              //> composeFunctor: [M[_], N[_]](fa: scalaz.Functor[M], fb: scalaz.Functor[N])s
                                                  //| calaz.Functor[[x]M[N[x]]]
 def composeFunctor[M[_],N[_]](fa: Functor[M], fb: Functor[N]): Functor[({type mn[x] = M[N[x]]})#mn] =   new Functor[({type mn[x] = M[N[x]]})#mn] {        def map[A,B](fab: M[N[A]])(f: A => B): M[N[B]] =           fa.map(n => fb.map   }                                              //> composeFunctor: [M[_], N[_]](fa: scalaz.Functor[M], fb: scalaz.Functor[N])s                                                  //| calaz.Functor[[x]M[N[x]]]

我们来解释一下:假若M,N都以Functor,那么M[N[A]]也是Functor,大家得以用M[N[A]].map来运算A值。看看上面包车型地铁例证:

大家来解释一下:倘若M,N都以Functor,那么M[N[A]]也是Functor,大家能够用M[N[A]].map来运算A值。看看上面包车型大巴事例:

1 val stringlen: String => Int = _.length           //> stringlen  : String => Int = <function1>
2 val optionInList = List("1".some,"12".some,"123".some)
3                                                   //> optionInList  : List[Option[String]] = List(Some(1), Some(12), Some(123))
4 
5 val mnFunctor = composeFunctor(Functor[List],Functor[Option])
6                                                   //> mnFunctor  : scalaz.Functor[[x]List[Option[x]]] = Exercises.monadtrans$$ano
7                                                   //| nfun$main$1$$anon$1@130d63be
8 mnFunctor.map(optionInList)(stringlen)            //> res3: List[Option[Int]] = List(Some(1), Some(2), Some(3))
1 val stringlen: String => Int = _.length           //> stringlen  : String => Int = <function1>2 val optionInList = List("1".some,"12".some,"123".some)3                                                   //> optionInList  : List[Option[String]] = List, Some, Some4 5 val mnFunctor = composeFunctor(Functor[List],Functor[Option])6                                                   //> mnFunctor  : scalaz.Functor[[x]List[Option[x]]] = Exercises.monadtrans$$ano7                                                   //| nfun$main$1$$anon$1@130d63be8 mnFunctor.map(optionInList)(stringlen)            //> res3: List[Option[Int]] = List, Some, Some

那么大家需求的Monad组合应该是这么的:M[N[A]],M,N都是Monad,如:Either[String,Option[A]],甚至是M[N[P[A]]],三层Monad。可惜,不是富有Monad都帮助函数组合的,看上边:

那便是说大家要求的Monad组合应该是那样的:M[N[A]],M,N都是Monad,如:Either[String,Option[A]],甚至是M[N[P[A]]],3层Monad。可惜,不是有所Monad都支持函数组合的,看上边:

 def composeMonad[M[_],N[_]](ma: Monad[M], mb: Monad[N]): Monad[({type mn[x] = M[N[x]]})#mn] =
   new Monad[({type mn[x] = M[N[x]]})#mn] {
     def point[A](a: => A) = ma.point(mb.point(a))
        def bind[A,B](mab: M[N[A]])(f: A => M[N[B]]): M[N[B]] =
           ??? ...
   }
 def composeMonad[M[_],N[_]](ma: Monad[M], mb: Monad[N]): Monad[({type mn[x] = M[N[x]]})#mn] =   new Monad[({type mn[x] = M[N[x]]})#mn] {     def point[A](a: => A) = ma.point(mb.point        def bind[A,B](mab: M[N[A]])(f: A => M[N[B]]): M[N[B]] =           ??? ...   }

实现M[N[A]].bind是不容许的,大家能够试试。那就堵死了函数组合那条路。难道我们就不大概使用M[N[A]]这样的for-comprehension了吗?毕竟像Either[String,Option[A]]诸如此类的组合是很宽泛的呀,比如说从数据库里读取那样的动作,有二种也许:取得数据、无多少None、爆发错误。无论如何我们先试试用for-comprehension:

实现M[N[A]].bind是不容许的,我们能够试试。那就堵死了函数组合那条路。难道大家就不能够使用M[N[A]]这样的for-comprehension了吗?毕竟像Either[String,Option[A]]如此那般的结缘是很常见的呦,比如说从数据Curry读取那样的动作,有三种也许:取得数据、无多少None、发生错误。无论怎样大家先试试用for-comprehension:

1 type Result[A] = String \/ Option[A]
2 val result: Result[Int] = 62.some.right           //> result  : Exercises.monadtxns.Result[Int] = \/-(Some(62))
3 for {
4     optionValue <- result
5 } yield {
6   for {
7       valueA <- optionValue
8   } yield valueA + 18                             //> res0: scalaz.\/[String,Option[Int]] = \/-(Some(80))
9 }
1 type Result[A] = String \/ Option[A]2 val result: Result[Int] = 62.some.right           //> result  : Exercises.monadtxns.Result[Int] = \/-3 for {4     optionValue <- result5 } yield {6   for {7       valueA <- optionValue8   } yield valueA + 18                             //> res0: scalaz.\/[String,Option[Int]] = \/-9 }

从下面可以明白大家无法不用两层for-comprehension才能运算A值。那么同理可得假若是M[N[P[A]]]就必要3层for-comprehension了。那就是所谓的“下阶梯式算法”(stair-stepping)。表面上来看stair-stepping会发出复杂臃肿的代码,丧失FP的简单优雅风格。但想深一层,若是内部3个Monad是会爆发副效用的如IO[Option[A]],那么地点的例证就改为那样:

从地点能够明白大家不能够不用两层for-comprehension才能运算A值。那么总而言之假若是M[N[P[A]]]就要求三层for-comprehension了。那正是所谓的“下阶梯式算法”(stair-stepping)。表面上来看stair-stepping会生出复杂臃肿的代码,丧失FP的不难优雅风格。但想深一层,要是内部一个Monad是会产生副成效的如IO[Option[A]],那么地点的例证就改成那样:

1 for {
2   optionData <- IO
3 } yield {
4   for {
5     data <- optionData
6   } yield Process(data)
7 }
1 for {2   optionData <- IO3 } yield {4   for {5     data <- optionData6   } yield Process7 }

我们见到在首先层运算里开始展览了IO运算,产生了负效应。那么以上的代码就不再是纯代码了,不可能保障函数组合。也等于说stair-stepping会产生不纯代码,违背了FP供给。此前我们早已探讨过 ReaderWriterState Monad,它是里德r,Writer,State四个Monad的3结合。在它的for-comprehension里的运算结果类型是ReaderWriterState一种,所以并未有stair-stepping忧虑。但我们亟须先创建1个新的品类(不是通过函数组合的新品类)。难道我们在行使不一样必要的for-comprehension时都急需重新创立一个新品类吗,那样不就损失了FP的代码重复使用特点了吗?不,scalaz提供的Monad
Transformer就是二个得力的化解方案。

大家看来在率先层运算里开始展览了IO运算,发生了负效应。那么以上的代码就不再是纯代码了,不大概维持函数组合。也正是说stair-stepping会生出不纯代码,违背了FP供给。从前大家早已研讨过ReaderWriterStateMonad,它是Reader,Writer,State八个Monad的组成。在它的for-comprehension里的演算结果类型是里德rWriterState1种,所以未有stair-stepping忧虑。但大家务必先成立三个新的项目(不是透过函数组合的新品类)。难道大家在采取分裂要求的for-comprehension时都亟待再行成立二个新品类吗,那样不就损失了FP的代码重复使用特点了呢?不,scalaz提供的Monad
Transformer正是3个得力的消除方案。

scalaz为许多type
class提供了Monad
Transformer,它们都是T尾缀命名如OptionT、EitherT、StateT…,大家得以经过Monad
Transformer来灵活地整合Monad。以OptionT为例:

scalaz为广大type
class提供了Monad
Transformer,它们都是T尾缀命名如OptionT、EitherT、StateT…,大家能够透过Monad
Transformer来灵活地结合Monad。以OptionT为例:

1 type Error[A] = \/[String, A]
2 type Result[A] = OptionT[Error, A]
3 
4 val result: Result[Int] = 62.point[Result]        //> result  : Exercises.monadtxns.Result[Int] = OptionT(\/-(Some(62)))
5 val transformed =
6   for {
7     value <- result
8   } yield value + 18                              //> transformed  : scalaz.OptionT[Exercises.monadtxns.Error,Int] = OptionT(\/-(S
9                                                   //| ome(80)))
1 type Error[A] = \/[String, A]2 type Result[A] = OptionT[Error, A]3 4 val result: Result[Int] = 62.point[Result]        //> result  : Exercises.monadtxns.Result[Int] = OptionT(\/-)5 val transformed =6   for {7     value <- result8   } yield value + 18                              //> transformed  : scalaz.OptionT[Exercises.monadtxns.Error,Int] = OptionT(\/-(S9                                                   //| ome

未来,运算A只须要壹层context了。Result就是经过Monad
Transformer产生的新类型。在地点的品类构建里,OptionT正是四个Monad
Transformer、Error是一定了Left类型的Either。因为Either有七个类型参数,大家其实也足以直接用type
lambda来表示Result[A]:

近年来,运算A只要求壹层context了。Result就是透过Monad
Transformer产生的新品类。在地方的类型营造里,OptionT就是贰个Monad
Transformer、Error是平昔了Left类型的Either。因为Either有四个门类参数,大家实在也足以向来用type
lambda来代表Result[A]:

type Result[A] = OptionT[({type l[x] = \/[String,x]})#l,A]
type Result[A] = OptionT[({type l[x] = \/[String,x]})#l,A]

可是那样写不但复杂,而且会潜移默化编写翻译器的系列推导(compiler
type inference)。

只是那样写不但复杂,而且会潜移默化编写翻译器的门类推导(compiler
type inference)。

值得注意的是,Monad
Transformer 类型的创设是由内向外反向的。比如上边的事例中OptionT是个Monad
Transformer,它的系列款式是OptionT[M[_],A]。OptionT实际上是用来营造M[Option[A]],在大家的例证里正是Either[Option[A]]。我们来看望一些常用Monad
Transformer的花色款式:

值得注意的是,Monad
Transformer 类型的创设是由内向外反向的。比如上面包车型大巴例证中OptionT是个Monad
Transformer,它的类型款式是OptionT[M[_],A]。OptionT实际上是用来营造M[Option[A]],在大家的例子里正是Either[Option[A]]。大家来探望一些常用Monad
Transformer的种类款式:

final case class OptionT[F[_], A](run: F[Option[A]]) {
...
final case class EitherT[F[_], A, B](run: F[A \/ B]) {
...
final case class ListT[F[_], A](run: F[List[A]]){
...
trait IndexedStateT[F[_], -S1, S2, A] { self =>
  /** Run and return the final value and state in the context of `F` */
  def apply(initial: S1): F[(S2, A)]
final case class OptionT[F[_], A](run: F[Option[A]]) {...final case class EitherT[F[_], A, B](run: F[A \/ B]) {...final case class ListT[F[_], A](run: F[List[A]]){...trait IndexedStateT[F[_], -S1, S2, A] { self =>  /** Run and return the final value and state in the context of `F` */  def apply(initial: S1): F[]

能够见到,Monad
Transformer
的重点功能就在重组run那个咱们誉为嵌入值了。F能够是别的一般Monad。在下边包车型地铁事例就改为了:

能够观察,Monad
Transformer
的重中之重成效就在结合run那几个大家誉为嵌入值了。F能够是其余一般Monad。在下面的事例就变成了:

OptionT[Either,A](run:
Either[Option[A]]),这个Either[Option[A]]正是大家的指标项目。而大家在操作时如在for-comprehension中运算时利用的档次则必须统壹为OptionT[Either,A]。

OptionT[Either,A](run:
Either[Option[A]]),这个Either[Option[A]]就是我们的对象项目。而笔者辈在操作时如在for-comprehension中运算时利用的门类则必须联合为OptionT[Either,A]。

我们怎么去创设Monad
Transformer类型值呢?大家能够用Applicative[MT].point只怕直接用塑造器格局如OptionT(…)

作者们怎样去营造Monad
Transformer类型值呢?我们得以用Applicative[MT].point可能直接用构建器形式如OptionT

//point升格
Applicative[Result].point(62)                     //> res0: Exercises.monadtxns.Result[Int] = OptionT(\/-(Some(62)))
//简写版本
62.point[Result]                                  //> res1: Exercises.monadtxns.Result[Int] = OptionT(\/-(Some(62)))
//会产生错误结果
None.point[Result]                                //> res2: Exercises.monadtxns.Result[None.type] = OptionT(\/-(Some(None)))
"Oh,shit!".left.point[Result]                     //> res3: Exercises.monadtxns.Result[scalaz.\/[String,Nothing]] = OptionT(\/-(So
                                                  //| me(-\/(Oh,shit!))))
//用构建器
OptionT((None: Option[Int]).point[Error])         //> res4: scalaz.OptionT[Exercises.monadtxns.Error,Int] = OptionT(\/-(None))
OptionT(none[Int].point[Error])                   //> res5: scalaz.OptionT[Exercises.monadtxns.Error,Int] = OptionT(\/-(None))
OptionT("Oh,shit!".left: Error[Option[Int]])      //> res6: scalaz.OptionT[Exercises.monadtxns.Error,Int] = OptionT(-\/(Oh,shit!))
//point升格Applicative[Result].point(62)                     //> res0: Exercises.monadtxns.Result[Int] = OptionT(\/-)//简写版本62.point[Result]                                  //> res1: Exercises.monadtxns.Result[Int] = OptionT(\/-)//会产生错误结果None.point[Result]                                //> res2: Exercises.monadtxns.Result[None.type] = OptionT(\/-(Some"Oh,shit!".left.point[Result]                     //> res3: Exercises.monadtxns.Result[scalaz.\/[String,Nothing]] = OptionT(\/-(So                                                  //| me(-\/)))//用构建器OptionT((None: Option[Int]).point[Error])         //> res4: scalaz.OptionT[Exercises.monadtxns.Error,Int] = OptionT)OptionT(none[Int].point[Error])                   //> res5: scalaz.OptionT[Exercises.monadtxns.Error,Int] = OptionT)OptionT("Oh,shit!".left: Error[Option[Int]])      //> res6: scalaz.OptionT[Exercises.monadtxns.Error,Int] = OptionT(-\/)

与重新创设另一个类型分歧的是,通过Monad
Transformer叠加Monad组合形成项指标操作仍旧选拔各组成Monad的操作函数,这一个函数运算结果类型任然是应和的Monad类型,所以需求有的荣升函数(lifting
functions)来统壹类型。而重建项目则持续了整合Monad的操作函数,它们的演算结果类型都与新建的这几个类型壹致。上边我们依旧用地点的那几个Either+Option例子来演示。我们把Either和Option叠加后根据分歧顺序能够发生Either[Option[A]]或者Option[Either[A]]二种结果类型,所以叠加顺序是这多少个首要的,因为那两种类型代表着完全不相同的意思:Either[Option[A]]表示1个运算结果能够是大功告成right只怕退步left,假若运算成功则赶回一个结出或空值;而Option[Either[A]]从字面上掌握好像是叁个运算可以回到二个成功或退步的运算又只怕再次回到空值,应该是尚未任何意义的四个品种。后边大家关系过用Monad
Transformer叠加Monad是由内向外反方向的:获取Either[Option[A]]就要求用OptionT[Either,A]。而且大家供给把Either和Option升格成OptionT[Either,A],看下边包车型地铁言传身教:

与重新创设另3个类型区别的是,通过Monad
Transformer叠加Monad组合形成品种的操作依旧接纳各组成Monad的操作函数,这几个函数运算结果类型任然是应和的Monad类型,所以须求壹些晋级函数(lifting
functions)来归并类型。而重建项目则继续了咬合Monad的操作函数,它们的演算结果类型都与新建的这一个项目1致。上边我们依然用位置的那些Either+Option例子来演示。大家把Either和Option叠加后依照差别顺序能够生出Either[Option[A]]或者Option[Either[A]]三种结果类型,所以叠加顺序是不行重大的,因为那两类别型代表着完全区别的含义:Either[Option[A]]意味着2个运算结果能够是马到功成right只怕战败left,假诺运算成功则赶回二个结实或空值;而Option[Either[A]]从字面上领会好像是一个运算能够再次回到八个成功或破产的演算又只怕重临空值,应该是一向不别的意义的二个品种。前边大家提到过用Monad
Transformer叠加Monad是由内向外反方向的:获取Either[Option[A]]就必要用OptionT[Either,A]。而且大家必要把Either和Option升格成OptionT[Either,A],看下边包车型地铁言传身教:

 1 type Error[A] = \/[String, A]
 2 type Result[A] = OptionT[Error, A]
 3 
 4 def getString: Option[String] = "Hello ".some     //> getString: => Option[String]
 5 def getResult: Error[String] = "how are you!".right
 6                                                   //> getResult: => Exercises.monadtxns.Error[String]
 7 val prg: Result[String] = for {
 8   s1 <- OptionT.optionT(getString.point[Error])
 9   s2 <- "World,".point[Result]
10   s3 <- getResult.liftM[OptionT]
11 } yield s1+s2+s3                                  //> prg  : Exercises.monadtxns.Result[String] = OptionT(\/-(Some(Hello World,how
12                                                   //|  are you!)))
13 prg.run                                           //> res0: Exercises.monadtxns.Error[Option[String]] = \/-(Some(Hello World,how a
14                                                   //| re you!))
 1 type Error[A] = \/[String, A] 2 type Result[A] = OptionT[Error, A] 3  4 def getString: Option[String] = "Hello ".some     //> getString: => Option[String] 5 def getResult: Error[String] = "how are you!".right 6                                                   //> getResult: => Exercises.monadtxns.Error[String] 7 val prg: Result[String] = for { 8   s1 <- OptionT.optionT(getString.point[Error]) 9   s2 <- "World,".point[Result]10   s3 <- getResult.liftM[OptionT]11 } yield s1+s2+s3                                  //> prg  : Exercises.monadtxns.Result[String] = OptionT(\/-(Some(Hello World,how12                                                   //|  are you!)))13 prg.run                                           //> res0: Exercises.monadtxns.Error[Option[String]] = \/-(Some(Hello World,how a14                                                   //| re you!))

率先,大家幸免了stair-stepping,直接运算s一+s二+s3。point、OptionT.optionT、liftM分别对String,Option,Either实行项目升格形成Result[String]
>>> OptionT[Error,String]。升格函数源代码如下:

先是,大家制止了stair-stepping,间接运算s壹+s二+s三。point、OptionT.optionT、liftM分别对String,Option,Either实行项目升格形成Result[String]
>>> OptionT[Error,String]。升格函数源代码如下:

trait ApplicativeIdV[A] extends Ops[A] {
    def point(implicit F: Applicative[F]): F[A] = Applicative[F].point(self)
...
trait OptionTFunctions {
  def optionT[M[_]] = new (({type λ[α] = M[Option[α]]})#λ ~> ({type λ[α] = OptionT[M, α]})#λ) {
    def apply[A](a: M[Option[A]]) = new OptionT[M, A](a)
  }
...
final class MonadOps[F[_],A] private[syntax](val self: F[A])(implicit val F: Monad[F]) extends Ops[F[A]] {
  ////

  def liftM[G[_[_], _]](implicit G: MonadTrans[G]): G[F, A] = G.liftM(self)
...
trait ApplicativeIdV[A] extends Ops[A] {    def point(implicit F: Applicative[F]): F[A] = Applicative[F].point...trait OptionTFunctions {  def optionT[M[_]] = new (({type λ[α] = M[Option[α]]})#λ ~> ({type λ[α] = OptionT[M, α]})#λ) {    def apply[A](a: M[Option[A]]) = new OptionT[M, A]  }...final class MonadOps[F[_],A] private[syntax](val self: F[A])(implicit val F: Monad[F]) extends Ops[F[A]] {  ////  def liftM[G[_[_], _]](implicit G: MonadTrans[G]): G[F, A] = G.liftM...

再看看组合的Monad是不是贯彻了效益叠加,假如大家加个None转换:

再看看组合的Monad是还是不是落到实处了职能叠加,倘诺大家加个None转换:

1 val prg: Result[String] = for {
2   s1 <- OptionT.optionT(getString.point[Error])
3   s0 <- OptionT(none[String].point[Error])  
4   s2 <- "World,".point[Result]
5   s3 <- getResult.liftM[OptionT]
6 } yield s1+s2+s3                                  //> prg  : Exercises.monadtxns.Result[String] = OptionT(\/-(None))
7 prg.run                                           //> res0: Exercises.monadtxns.Error[Option[String]] = \/-(None)
1 val prg: Result[String] = for {2   s1 <- OptionT.optionT(getString.point[Error])3   s0 <- OptionT(none[String].point[Error])  4   s2 <- "World,".point[Result]5   s3 <- getResult.liftM[OptionT]6 } yield s1+s2+s3                                  //> prg  : Exercises.monadtxns.Result[String] = OptionT)7 prg.run                                           //> res0: Exercises.monadtxns.Error[Option[String]] = \/-

加个Left效果:

加个Left效果:

1 val prg: Result[String] = for {
2   s1 <- OptionT.optionT(getString.point[Error])
3   s0 <- OptionT("Catch Error!".left: Error[Option[String]])
4   s2 <- "World,".point[Result]
5   s3 <- getResult.liftM[OptionT]
6 } yield s1+s2+s3                                  //> prg  : Exercises.monadtxns.Result[String] = OptionT(-\/(Catch Error!))
7 prg.run                                           //> res0: Exercises.monadtxns.Error[Option[String]] = -\/(Catch Error!)
1 val prg: Result[String] = for {2   s1 <- OptionT.optionT(getString.point[Error])3   s0 <- OptionT("Catch Error!".left: Error[Option[String]])4   s2 <- "World,".point[Result]5   s3 <- getResult.liftM[OptionT]6 } yield s1+s2+s3                                  //> prg  : Exercises.monadtxns.Result[String] = OptionT(-\/(Catch Error!))7 prg.run                                           //> res0: Exercises.monadtxns.Error[Option[String]] = -\/(Catch Error!)

确实,用Monad
Transformer组合Monad后方可兑现成员Monad的作用叠加。

真正,用Monad
Transformer组合Monad后方可达成成员Monad的效果叠加。

可是,在实际应用中两层以上的Monad组合仍旧比较普遍的。Monad
Transformer自己正是Monad,能够延续与另二个Monad组合,只要用那个Monad的Transformer就行了。例如大家在地点的例证里再追加1层State,最终形成贰个三层类型:State[Either[Option[A]]]。依据上面包车型客车经验,堆砌Monad是由内向外的,大家先组合
StateEither >>>
StateT[Either,A],然后再得出组合:OptionT[StateEither,A]。大家来演示一下:

而是,在实际应用中两层以上的Monad组合如故比较广泛的。Monad
Transformer本人正是Monad,能够持续与另二个Monad组合,只要用那几个Monad的Transformer就行了。例如我们在地点的例证里再追加一层State,最后形成叁个3层类型:State[Either[Option[A]]]。根据上边包车型大巴经验,堆砌Monad是由内向外的,我们先组合
StateEither >>>
StateT[Either,A],然后再得出组合:OptionT[StateEither,A]。大家来演示一下:

先重新命名(alias)一些类:

先重新命名壹些类:

type StringEither[A] = String \/ A
type StringEitherT[M[_],A] = EitherT[M,String,A]
type IntState[A] = State[Int,A]
type IntStateT[M[_],A] = StateT[M,Int,A]
type StateEither[A] = StringEitherT[IntState,A]
type StateEitherOption[A] = OptionT[StateEither,A]
type StringEither[A] = String \/ Atype StringEitherT[M[_],A] = EitherT[M,String,A]type IntState[A] = State[Int,A]type IntStateT[M[_],A] = StateT[M,Int,A]type StateEither[A] = StringEitherT[IntState,A]type StateEitherOption[A] = OptionT[StateEither,A]

由Option,Either,State组合而成的Monad要求相关的升级换代函数(lifting
functions):

由Option,Either,State组合而成的Monad要求有关的升级函数(lifting
functions):

//常量升格
val m: StateEitherOption[Int] = 3.point[StateEitherOption]
                                                  //> m  : Exercises.monad_txnfm.StateEitherOption[Int] = OptionT(EitherT(scalaz.p
                                                  //| ackage$StateT$$anon$1@4f638935))
//option类升格
val o: Option[Int] = 3.some                       //> o  : Option[Int] = Some(3)
val o1: StateEither[Option[Int]]= o.point[StateEither]
                                                  //> o1  : Exercises.monad_txnfm.StateEither[Option[Int]] = EitherT(scalaz.packag
                                                  //| e$StateT$$anon$1@694abbdc)

val o2: StateEitherOption[Int] = OptionT.optionT(o1)
                                                  //> o2  : Exercises.monad_txnfm.StateEitherOption[Int] = OptionT(EitherT(scalaz.
                                                  //| package$StateT$$anon$1@694abbdc))
//val o2: OptionT[StateEither,Int] = OptionT.optionT(o1)

//either类升格
val e: StringEither[Int] = 3.point[StringEither]  //> e  : Exercises.monad_txnfm.StringEither[Int] = \/-(3)
val e1: IntState[StringEither[Int]] = e.point[IntState]
                                                  //> e1  : Exercises.monad_txnfm.IntState[Exercises.monad_txnfm.StringEither[Int]
                                                  //| ] = scalaz.package$StateT$$anon$1@52bf72b5
val e2: StateEither[Int] = EitherT.eitherT(e1)    //> e2  : Exercises.monad_txnfm.StateEither[Int] = EitherT(scalaz.package$StateT
                                                  //| $$anon$1@52bf72b5)
//val e2: StringEitherT[IntState,Int] = EitherT.eitherT(e1)
val e3: StateEitherOption[Int] = e2.liftM[OptionT]//> e3  : Exercises.monad_txnfm.StateEitherOption[Int] = OptionT(EitherT(scalaz.
                                                  //| IndexedStateT$$anon$10@2d7275fc))
//val e3: OptionT[StateEither,Int] = e2.liftM[OptionT]
//state类升格
val s: IntState[Int] = get[Int]                   //> s  : Exercises.monad_txnfm.IntState[Int] = scalaz.package$State$$anon$3@7e0
                                                  //| 7db1f
val s1: StateEither[Int] = s.liftM[StringEitherT] //> s1  : Exercises.monad_txnfm.StateEither[Int] = EitherT(scalaz.IndexedStateT
                                                  //| $$anon$10@8f4ea7c)
//val s1: StringEitherT[IntState,Int] = s.liftM[StringEitherT]
val s2: StateEitherOption[Int] = s1.liftM[OptionT]//> s2  : Exercises.monad_txnfm.StateEitherOption[Int] = OptionT(EitherT(scalaz
                                                  //| .IndexedStateT$$anon$10@436813f3))
//val s2: OptionT[StateEither,Int] = s1.liftM[OptionT]
//把State升格成StateT
val s3: IntStateT[StringEither,Int] = get[Int].lift[StringEither]
                                                  //> s3  : Exercises.monad_txnfm.IntStateT[Exercises.monad_txnfm.StringEither,In
                                                  //| t] = scalaz.IndexedStateT$$anon$7@10e31a9a
//常量升格val m: StateEitherOption[Int] = 3.point[StateEitherOption]                                                  //> m  : Exercises.monad_txnfm.StateEitherOption[Int] = OptionT(EitherT(scalaz.p                                                  //| ackage$StateT$$anon$1@4f638935))//option类升格val o: Option[Int] = 3.some                       //> o  : Option[Int] = Someval o1: StateEither[Option[Int]]= o.point[StateEither]                                                  //> o1  : Exercises.monad_txnfm.StateEither[Option[Int]] = EitherT(scalaz.packag                                                  //| e$StateT$$anon$1@694abbdc)val o2: StateEitherOption[Int] = OptionT.optionT                                                  //> o2  : Exercises.monad_txnfm.StateEitherOption[Int] = OptionT(EitherT(scalaz.                                                  //| package$StateT$$anon$1@694abbdc))//val o2: OptionT[StateEither,Int] = OptionT.optionT//either类升格val e: StringEither[Int] = 3.point[StringEither]  //> e  : Exercises.monad_txnfm.StringEither[Int] = \/-val e1: IntState[StringEither[Int]] = e.point[IntState]                                                  //> e1  : Exercises.monad_txnfm.IntState[Exercises.monad_txnfm.StringEither[Int]                                                  //| ] = scalaz.package$StateT$$anon$1@52bf72b5val e2: StateEither[Int] = EitherT.eitherT    //> e2  : Exercises.monad_txnfm.StateEither[Int] = EitherT(scalaz.package$StateT                                                  //| $$anon$1@52bf72b5)//val e2: StringEitherT[IntState,Int] = EitherT.eitherTval e3: StateEitherOption[Int] = e2.liftM[OptionT]//> e3  : Exercises.monad_txnfm.StateEitherOption[Int] = OptionT(EitherT(scalaz.                                                  //| IndexedStateT$$anon$10@2d7275fc))//val e3: OptionT[StateEither,Int] = e2.liftM[OptionT]//state类升格val s: IntState[Int] = get[Int]                   //> s  : Exercises.monad_txnfm.IntState[Int] = scalaz.package$State$$anon$3@7e0                                                  //| 7db1fval s1: StateEither[Int] = s.liftM[StringEitherT] //> s1  : Exercises.monad_txnfm.StateEither[Int] = EitherT(scalaz.IndexedStateT                                                  //| $$anon$10@8f4ea7c)//val s1: StringEitherT[IntState,Int] = s.liftM[StringEitherT]val s2: StateEitherOption[Int] = s1.liftM[OptionT]//> s2  : Exercises.monad_txnfm.StateEitherOption[Int] = OptionT(EitherT(scalaz                                                  //| .IndexedStateT$$anon$10@436813f3))//val s2: OptionT[StateEither,Int] = s1.liftM[OptionT]//把State升格成StateTval s3: IntStateT[StringEither,Int] = get[Int].lift[StringEither]                                                  //> s3  : Exercises.monad_txnfm.IntStateT[Exercises.monad_txnfm.StringEither,In                                                  //| t] = scalaz.IndexedStateT$$anon$7@10e31a9a

地方又多介绍了StateT.lift,
EitherT.eitherT八个升级函数:

上边又多介绍了StateT.lift,
EitherT.eitherT八个升级函数:

  def lift[M[_]: Applicative]: IndexedStateT[({type λ[α]=M[F[α]]})#λ, S1, S2, A] = new IndexedStateT[({type λ[α]=M[F[α]]})#λ, S1, S2, A] {
    def apply(initial: S1): M[F[(S2, A)]] = Applicative[M].point(self(initial))
  }
...
trait EitherTFunctions {
  def eitherT[F[_], A, B](a: F[A \/ B]): EitherT[F, A, B] = EitherT[F, A, B](a)
...
  def lift[M[_]: Applicative]: IndexedStateT[({type λ[α]=M[F[α]]})#λ, S1, S2, A] = new IndexedStateT[({type λ[α]=M[F[α]]})#λ, S1, S2, A] {    def apply(initial: S1): M[F[]] = Applicative[M].point(self  }...trait EitherTFunctions {  def eitherT[F[_], A, B](a: F[A \/ B]): EitherT[F, A, B] = EitherT[F, A, B]...

咱俩在上头例子的底子上加码一层State效果后再试用一下这几个进步函数:

咱俩在地点例子的根基上平添1层State效果后再试用一下这个提高函数:

 1 def getString: Option[String] = "Hello ".some     //> getString: => Option[String]
 2 def getResult: StringEither[String] = "how are you!".right[String]
 3                                                   //> getResult: => Exercises.monad_txnfm.StringEither[String]
 4 def modState(s:Int): IntState[Unit] = put(s)      //> modState: (s: Int)Exercises.monad_txnfm.IntState[Unit]
 5 val prg: StateEitherOption[String] = for {
 6   s1 <- OptionT.optionT(getString.point[StateEither])
 7   s2 <- "World,".point[StateEitherOption]
 8   s3 <- (EitherT.eitherT(getResult.point[IntState]): StateEither[String]).liftM[OptionT]
 9   _ <- (modState(99).liftM[StringEitherT]: StateEither[Unit]).liftM[OptionT]
10 } yield s1+s2+s3                                  //> prg  : Exercises.monad_txnfm.StateEitherOption[String] = OptionT(EitherT(sc
11                                                   //| alaz.IndexedStateT$$anon$10@158d2680))
12 prg.run                                           //> res0: Exercises.monad_txnfm.StateEither[Option[String]] = EitherT(scalaz.In
13                                                   //| dexedStateT$$anon$10@158d2680)
 1 def getString: Option[String] = "Hello ".some     //> getString: => Option[String] 2 def getResult: StringEither[String] = "how are you!".right[String] 3                                                   //> getResult: => Exercises.monad_txnfm.StringEither[String] 4 def modState: IntState[Unit] = put      //> modState: Exercises.monad_txnfm.IntState[Unit] 5 val prg: StateEitherOption[String] = for { 6   s1 <- OptionT.optionT(getString.point[StateEither]) 7   s2 <- "World,".point[StateEitherOption] 8   s3 <- (EitherT.eitherT(getResult.point[IntState]): StateEither[String]).liftM[OptionT] 9   _ <- (modState(99).liftM[StringEitherT]: StateEither[Unit]).liftM[OptionT]10 } yield s1+s2+s3                                  //> prg  : Exercises.monad_txnfm.StateEitherOption[String] = OptionT(EitherT(sc11                                                   //| alaz.IndexedStateT$$anon$10@158d2680))12 prg.run                                           //> res0: Exercises.monad_txnfm.StateEither[Option[String]] = EitherT(scalaz.In13                                                   //| dexedStateT$$anon$10@158d2680)

科学,类型对了,prg能够透过编译,但未免复杂了点。笔者花了很多时间去匹配那些项目,因为须求连接提高。总之,即使蒙受四层以上的Monad组合,代码会复杂成怎么着。在那之中重大还是在各连串型的升官。那我们还是回想一下这个升高函数吧:

不错,类型对了,prg能够透过编写翻译,但未免复杂了点。小编花了不可胜举日子去匹配这个体系,因为急需连接升高。同理可得,就算遭遇四层以上的Monad组合,代码会复杂成什么样。在那之中重要如故在各类别型的升级。那大家依然回看一下这几个升高函数吧:

 

A.point[F[_]]
>>> F[A] “hi”.point[Option] = Option[String] =
Some

A.point[F[_]]
>>> F[A]   “hi”.point[Option] = Option[String] =
Some(“hi”)

M[A].liftM[T[_[_],_]]
>>> T[M,A] List.liftM[OptionT] = OptionT[List,Int] =
OptionT(List

 

OptionT.optionT(M[Option[A]])
>>> OptionT[M,A] OptionT.optionT(List = OptionT[List,Int] =
OptionT(List

M[A].liftM[T[_[_],_]]
>>> T[M,A]   List(3).liftM[OptionT] = OptionT[List,Int] =
OptionT(List(Some(3)))

EitherT.eitherT(M[Either[A]])
>>> EitherT[M,A] EitherT.eitherT(List(3.right[String])) =
EitherT(List

 

State.lift[M[A]] >>>
StateT[M,A] get[Int].lift[Option] =
StateT[Option,Int]

OptionT.optionT(M[Option[A]])
>>> OptionT[M,A]  OptionT.optionT(List(3.some)) =
OptionT[List,Int] = OptionT(List(Some(3)

专注:以上采纳了影像类型表述

 

EitherT.eitherT(M[Either[A]])
>>> EitherT[M,A] EitherT.eitherT(List(3.right[String])) =
EitherT(List(\/-(3))

 

State.lift[M[A]] >>>
StateT[M,A]  get[Int].lift[Option] =
StateT[Option,Int]

 

注意:以上接纳了影像类型表述

 

 

 

 

 

 

 

 

 

 

相关文章