了解组合Monads的理解示例

时间:2015-04-12 17:32:47

标签: scala monads

J. Abrahamson为我的composing-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]

在构建for-comprehension时,是找到结束类型的典型方法,即Either[String, Int],然后让每个flatMap调用具有该类型吗?

1 个答案:

答案 0 :(得分:1)

如果您的意思是Either[Boolean, Int]代替Either[Any, Int],那么&#34;您无法获得所需的内容&#34;。即使是正确投影,其组成(如您的示例中)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的左侧类型(因此?Boolean?变为Any),否则它不会#39}甚至工作。在回答您的问题时,flatMap此处不能AA = Boolean,因为A已经至少String,并且如第一个示例所示,实际上可能是{{} 1}}。

顺便说一下,在这个例子中没有monad组合 - String可能只是一个算子。更重要的是,您在这里用r撰写RightProjection,因此他们会自动上下班。

推断RightProjection的唯一方法是使用Boolean杀死String类型 - 只有当您确定Nothing始终为x时才能这样做:

Right

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