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

  中间插播了几乎首scalaz数据类型,现在同时如果返回Monad专题。因为FP的表征就是是Monad式编程(Monadic
programming),所以必须尽知情认识Monad、熟练掌握Monad运用。曾经看到同样截对Monad的叙说:“Monadic
for-comprehension就是一模一样种植嵌入式编程语言,由它们的Monad提供它的语法”。但如各一样种植Monad的for-comprehension都独立提供相同模仿语法的话,这种编程语言就显得特别枯燥、功能简单了。那么既是FP,我们当好由此函数组合(function
composition)来拿成千上万简易的for-comprehension组合成一学到的编程语言吧?比如这样:Option[A]
>>> IO[Option[A]] >>>
IO[Either[String,Option[A]]。恰恰,Monad是未支持函数组合的。先了解一下函数组合:Functor是得做的,我们好拿fa和fb组合成一个复复杂的Functor
fab,我们来证实一下:

  中间插播了几乎首scalaz数据类型,现在以要回Monad专题。因为FP的特色就是是Monad式编程(Monadic
programming),所以要尽知晓认识Monad、熟练掌握Monad运用。曾经看到同样段对Monad的叙说:“Monadic
for-comprehension就是相同栽嵌入式编程语言,由它们的Monad提供它的语法”。但若是每一样栽Monad的for-comprehension都独立提供相同模拟语法的话,这种编程语言就显分外枯燥、功能简单了。那么既是FP,我们当可以经过函数组合(function
composition)来拿广大简单易行的for-comprehension组合成一效到的编程语言吧?比如这样:Option[A]
>>> IO[Option[A]] >>>
IO[Either[String,Option[A]]。恰恰,Monad是不支持函数组合的。先了解一下函数组合:Functor是可结合的,我们可以拿fa和fb组合成一个还复杂的Functor
fab,我们来证实一下:

 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(fab)(n => fb.map(n)(f))
   }                                              //> 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(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))

那我们得之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]]],三叠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(a))
        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]]这么的结缘是深普遍的哟,比如说从数据库里读取这样的动作,有几种植或:取得数据、无多少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] = \/-(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 }

起地方可以了解我们须用半重叠for-comprehension才会运算A值。那么可想而知如果是M[N[P[A]]]纵使需要三重叠for-comprehension了。这即是所谓的“下阶梯式算法”(stair-stepping)。表面上来拘禁stair-stepping会发生复杂臃肿的代码,丧失FP的简要优雅风格。但想大一重叠,如果内部一个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 <- IO
3 } yield {
4   for {
5     data <- optionData
6   } yield Process(data)
7 }

咱们看来于第一重合运算里展开了IO运算,产生了负效应。那么以上之代码就不再是纯代码了,无法保障函数组合。也就是说stair-stepping会来不纯代码,违背了FP要求。之前我们都讨论过 ReaderWriterState Monad,它是Reader,Writer,State三独Monad的三结合。在它们的for-comprehension里的运算结果类型是ReaderWriterState一种,所以没有stair-stepping忧虑。但我们务必事先创造一个新的种(不是由此函数组合的新类型)。难道我们于使不同要求的for-comprehension时还用重新创设一个初类型也,这样非纵损失了FP的代码重复使用特点了呢?不,scalaz提供的Monad
Transformer就是一个使得的化解方案。

咱俩视于率先交汇运算里展开了IO运算,产生了负效应。那么以上之代码就不再是纯代码了,无法保全函数组合。也就是说stair-stepping会发生不纯粹代码,违背了FP要求。之前我们既讨论过 ReaderWriterState Monad,它是Reader,Writer,State三只Monad的组合。在她的for-comprehension里的运算结果类型是ReaderWriterState一种植,所以没stair-stepping忧虑。但我们亟须先创造一个初的花色(不是经过函数组合的新品类)。难道我们以使不同要求的for-comprehension时犹要还创设一个初品类也,这样非纵损失了FP的代码重复使用特点了也?不,scalaz提供的Monad
Transformer就是一个使得的化解方案。

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(\/-(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)))

现今,运算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[(S2, A)]

好望,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(\/-(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!))

同更构建另一个档次不同之是,通过Monad
Transformer叠加Monad组合形成项目的操作还是以各做Monad的操作函数,这些函数运算结果类型任然是呼应之Monad类型,所以要一些升迁函数(lifting
functions)来归并路。而重建项目则继续了做Monad的操作函数,它们的运算结果类型且同新建的这个项目一致。下面我们还是用者的这Either+Option例子来演示。我们把Either和Option叠加后本不同顺序可以生Either[Option[A]]或者Option[Either[A]]片种植结果类型,所以叠加顺序是那个主要之,因为当时有限栽类型代表在了不同之含义:Either[Option[A]]代表一个运算结果好是成功right或者失败left,如果运算成功则归一个结实要空值;而Option[Either[A]]自从字面上了解好像是一个运算可以回来一个中标还是黄的运算而或者返回空值,应该是无其它意义之一个档次。前面我们干过用Monad
Transformer叠加Monad是由于外往外倒方向的:获取Either[Option[A]]不畏用为此OptionT[Either,A]。而且我们用把Either和Option升格成OptionT[Either,A],看下的示范:

和重构建另一个列不同的凡,通过Monad
Transformer叠加Monad组合形成门类的操作照旧采用各组成Monad的操作函数,这些函数运算结果类型任然是相应之Monad类型,所以用部分提升函数(lifting
functions)来统一路。而重建项目则持续了成Monad的操作函数,它们的演算结果类型且与新建的是路一致。下面我们要用地方的这个Either+Option例子来演示。我们将Either和Option叠加后按照不同顺序可以生Either[Option[A]]或者Option[Either[A]]有数种结果类型,所以叠加顺序是蛮重大的,因为就简单种档次代表正在完全不同的意义:Either[Option[A]]代表一个运算结果好是成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,how
12                                                   //|  are you!)))
13 prg.run                                           //> res0: Exercises.monadtxns.Error[Option[String]] = \/-(Some(Hello World,how a
14                                                   //| re you!))

先是,我们避免了stair-stepping,直接运算s1+s2+s3。point、OptionT.optionT、liftM分别指向String,Option,Either进行路升格形成Result[String]
>>> OptionT[Error,String]。升格函数源代码如下:

首先,我们避免了stair-stepping,直接运算s1+s2+s3。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(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)
...

又省组合的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(\/-(None))
7 prg.run                                           //> res0: Exercises.monadtxns.Error[Option[String]] = \/-(None)

加个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就推行了。例如我们以地方的例证里更增加一重合State,最终形成一个老三交汇类型:State[Either[Option[A]]]。按照上面的经验,堆砌Monad是由外为他的,我们事先做
StateEither >>>
StateT[Either,A],然后再次得出组合:OptionT[StateEither,A]。我们来演示一下:

只是,在实质上采用中有数叠以上的Monad组合或于常见的。Monad
Transformer本身就是Monad,可以继承同其他一个Monad组合,只要用此Monad的Transformer就执行了。例如我们以方的例子里更多一重合State,最终形成一个老三交汇类型:State[Either[Option[A]]]。按照地方的经验,堆砌Monad是由于外往外的,我们事先结
StateEither >>>
StateT[Either,A],然后再得出组合:OptionT[StateEither,A]。我们来演示一下:

先期重新命名(alias)一些像样:

先行重新命名(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 \/ 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]

鉴于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] = 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

地方又多介绍了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[(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)
...

我们于上头例子的根底及平添一层State效果后又试用一下这些提升函数:

咱们在方例子的功底及搭一重叠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(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)

是的,类型对了,prg可以由此编译,但不休复杂了点。我花费了诸多时空错开匹配这些类别,因为待连接提升。可想而知,如果遇到四层以上之Monad组合,代码会复杂成什么。其中最主要要于各种类型的升级。那咱们还是回顾一下这些提升函数吧:

毋庸置疑,类型对了,prg可以通过编译,但非休复杂了接触。我花费了诸多工夫错开匹配这些类别,因为急需连接提升。可想而知,如果赶上四层以上的Monad组合,代码会复杂成什么。其中重大要在各种类型的升级。那咱们或回顾一下这些提升函数吧:

 

 

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

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

 

 

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

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

 

 

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

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))

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]

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

 

 

只顾:以上采用了影像类型表述

留意:以上采用了形象类型表述

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相关文章