繁体   English   中英

以理解单子构成的理解示例

[英]For Comprehension Example to Understand Composing Monads

J.亚伯拉罕森(J. Abrahamson)对我的“ monads-v-applicative-functors”问题作了深入解答。

我获得了一些直觉,但我不完全理解他的有益回答。

鉴于以下Either

scala> x
res0: Either[String,Int] = Right(100)

scala> err
res1: Either[Boolean,Int] = Left(false)

我试图将它们链接在一起:

scala> for {
     |   xx <- x.right
     |   yy <- err.right
     | } yield xx + yy
res3: scala.util.Either[Any,Int] = Left(false)

但是,我当然不想要Either[Any, Int] 但是我们得到Any ,因为据我了解, Either[String, Int]Either[Boolean, Int]的父代是Either[Any, Int]

在构建理解时,通常的方法是找到结束类型,即Either[String, Int] ,然后使每个flatMap调用具有该类型吗?

如果您是说要Either[Boolean, Int]而不是Either[Any, Int] ,则“您不能总是得到想要的”。 组成相同(如您的示例中所示)的Either类型(但有些其他值)都可能返回String而不是Boolean即使对于正确的投影也是如此:

scala> val x: Either[String,Int] = Left("aaa")
x: Either[String,Int] = Left(aaa)

scala> val r: Either[Boolean,Int] = Right(100)
r: Either[Boolean,Int] = Right(100)

scala> for {
     |    xx <- x.right
     |    yy <- r.right //you may swap xx and yy - it doesn't matter for this example, which means that flatMap could be called on any of it         
     | } yield yy + xx
res21: scala.util.Either[Any,Int] = Left(aaa)

因此, Either[Any,Int]确实是正确的,并且它的终端类型尽可能小。

简化后的版本:

scala> x.right.flatMap(xx => r.right.map(_ + xx))
res27: scala.util.Either[Any,Int] = Left(aaa)

Monad的flatMap签名:

flatMap[AA >: A, Y](f: (B) ⇒ Either[AA, Y]): Either[AA, Y]

通过类型:

flatMap[Any >: String, Int](f: (Int) ⇒ Either[?Boolean?, Int]): Either[Any, String]

AA >: A在这里是完全合法的,因为它允许f = r.right.map(_ + xx)返回大于String left类型(因此, ?Boolean?变成Any ),否则它甚至无法工作。 在回答您的问题时,这里的flatMap不能具有AA = Boolean ,因为A已经至少是String ,并且如第一个示例所示,实际上可以是String

而且,顺便说一句,在此示例中没有monad组成r可能只是一个函子。 更重要的是,您在这里将RightProjectionRightProjection组合RightProjection ,以便它们自动进行通勤。

推断Boolean的唯一方法是使用Nothing杀死String类型-仅在确保x始终为Right才能这样做:

scala> val x: Either[Nothing,Int] = Right(100)
x: Either[Nothing,Int] = Right(100)

scala> val r: Either[Boolean,Int] = Left(false)
r: Either[Boolean,Int] = Left(false)

scala> for {
     |    yy <- r.right
     |    xx <- x.right  
     |        
     | } yield yy + xx
res24: scala.util.Either[Boolean,Int] = Left(false)

然后,您当然不能放字符串,这是完全正确的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM