使用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)
很高兴,通过使用left
和right
投影,可以使用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子句失败了,至少我尝试使用它的方式。
有没有人解释为什么这种设计是这样的?
答案 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]
,你就永远不会产生左值。