函数式编程 - 为什么 Scala 的 Both.RightProjection#filter 不返回 Both?



使用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投影,可以用于理解(通过投影的"任一"的有偏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方法返回"非此即彼"吗?我本以为以下会起作用:

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<-er.right如果r>2}产生r*2

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

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

这使if子句在for compensation中的使用失败,至少我试图使用它的方式是这样的

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

这可以归结为这样一个事实:如果您有一个Right(b),但您的筛选谓词失败了,那么您就没有值可以放在Left中。

您可能会设想一个适用于Either[String, Int]情况的实现,通过默认值Left("")失败。Scala标准库不具备为您生成值的功能,因为它不包含诸如monoid之类的概念,该概念将确定类型的"空"值。

Scalaz库确实包括一个monoid类型类,版本7还包括一个右偏析取类型/[A, B](同构于Either[A, B]),它有一个filter方法,如果左类型是monoid:

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

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

最新更新