6

使用 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)

很棒的是,通过使用leftandright投影,可以使用 for-comprehensions(通过投影 Either 的有偏单子):

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: error: value * is not a member of Either[Nothing,Int] for { r <- er.right if r > 2 } yield r * 2

看起来底层调用Either.RightProjection#filter实际上返回了一个Option

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

这破坏了在 for-comprehension 中使用 if 子句,至少是我尝试使用它的方式。

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

4

1 回答 1

12

归结为这样一个事实,如果您有 a Right(b),但您的过滤谓词失败,则您没有任何价值可放入 a Left

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

Scalaz库确实包含一个 monoid 类型类,版本 7 还包含一个右偏析取类型\/[A, B]与 同构Either[A, B]),它有一个filter方法 iff 左类型是一个幺半群:

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

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

于 2013-02-07T19:01:01.913 回答