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
调用具有该类型吗?
答案 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
然后,当然你不能放字符串,这是完全正确的。