2015-04-12 51 views
0

J. Abrahamson为我的composing-monads-v-applicative-functors问题提供了深入的答案。理解构成Monads的理解示例

我获得了一些直觉,但我并没有完全理解他的有用答案。

鉴于以下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调用都具有该类型?

回答

1

如果你的意思是你想要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) 

单子的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(so ?Boolean?变成Any),否则它甚至不能工作。回答你的问题,flatMap这里不能有AA = Boolean,因为A已经至少String,并且如第一个例子所示,实际上可以是String

而顺便说一下,在这个例子中没有monads构成 - r可能只是一个仿函数。更重要的是,你在这里撰写RightProjectionRightProjection,所以他们自动通勤。

到inferr Boolean的唯一方法是杀死String型与Nothing - 你可以做的,只有当你确定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) 

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