为什么Scala的Either.RightProjection#filter没有返回Either?

时间:2013-02-07 18:36:03

标签: scala functional-programming

使用Scala 2.9.1,考虑以下两个Either实例:

scala> val er: Either[String, Int] = Right(1)
er: Either[String,Int] = Right(1)

scala> val el: Either[String, Int] = Left("a")
el: Either[String,Int] = Left(a)

很高兴,通过使用leftright投影,可以使用for-comprehensions(通过投射Either的偏向monad):

scala> for { r <- er.right } yield r * 2
res6: Product with Either[String,Int] with Serializable = Right(2)

scala> for { r <- el.right } yield r * 2
res7: Product with Either[String,Int] with Serializable = Left(a)

有人可以向我解释为什么决定不让filter方法返回Either吗?我原本期望以下工作:

scala> for { r <- er.right if r > 2 } yield r * 2 // r is NOT greater than 2!
res8: Product with Either[String,Int] with Serializable = Left(a)

相反,您会收到以下错误:     :9:错误:值*不是[Nothing,Int]的成员                   对于{r&lt; - er.right如果r&gt; 2}收益率r * 2

Either.RightProjection#filter中的基础调用似乎实际上返回Option

scala> er.right.filter(_ > 2)
res9: Option[Either[Nothing,Int]] = None

这使得在for-comprehension中使用if子句失败了,至少我尝试使用它的方式。

有没有人解释为什么这种设计是这样的?

1 个答案:

答案 0 :(得分:12)

归结为这样一个事实,即如果你有一个Right(b),但你的过滤谓词失败了,那么你就无法放入Left

您可能会想象一个适用于Either[String, Int]案例的实现,但默认值为Left("")失败。 Scala标准库没有为您生成值的功能,因为它不包含诸如monoid之类的概念,它将确定类型的“空”值。

Scalaz库确实包含一个monoid类型类,而版本7也包含一个右偏的析取类型\/[A, B](同形为Either[A, B]),其中filter方法如果左类型是幺半群:

scala> \/.right[String, Int](1).filter(_ > 2)
res1: scalaz.\/[String,Int] = -\/()

但是对于一般情况你不能这样做 - 如果你有Either[Nothing, Int],你就永远不会产生左值。