我有兴趣了解设计决策为什么scala.Either
不作为单子完成。已经存在一些关于如何右偏的讨论Either
,例如:
但是提到了太多细节,我无法完整地了解为什么要这样做。有人可以概述一下偏右的好处,Either
这样做的问题以及不偏右的好处Either
(如果它们甚至存在的话)吗?
我有兴趣了解设计决策为什么scala.Either
不作为单子完成。已经存在一些关于如何右偏的讨论Either
,例如:
但是提到了太多细节,我无法完整地了解为什么要这样做。有人可以概述一下偏右的好处,Either
这样做的问题以及不偏右的好处Either
(如果它们甚至存在的话)吗?
我认为它只是归结为最小惊讶原则。使用Either
来编码成功或失败显然是人们所做的事情,但它并不是Either
. 事实上,除了传统之外,没有太多的Right
成功和Left
失败的理由。正如adelbertc 上面提到的评论,scalaz 有Validation
专门编码这个。
为了进一步证明上述 POLA 声明的合理性,请使用以下代码:
def foo(): Either[Int, Int] = Right(1)
def bar(j: Int): Either[Int, Int] = Left(1)
def baz(z: Int): Either[Int, Int] = Right(3)
// Result is Left(1)
for (a <- foo().right; b <- bar(a).right; c <- baz(b).right) yield c
这是编译的,因为我在表达式中使用了.right
投影。for
这是有道理的Left(1)
inbar
是失败的情况,所以这就是结果,但想象一下如果Either
是Right
-biased。.right
上面的代码将在没有表达式中的投影的情况下编译,例如:
for (a <- foo(); b <- bar(a); c <- baz(b)) yield c
如果您Either
在代码中使用的只是“一种或另一种”类型,您会惊讶于 (1) 这会编译的事实和 (2) 它返回Left(1)
并且似乎从不执行的事实baz
。
总之,Validation
如果你想用它Either
来编码成功或失败,请使用。
我不知道这是否是最初的原因,但至少有一个很好的理由。在 Scalafor
中,为了获得完整的功能,理解需要更多的参数而不是单子。特别是,有像
for (a <- ma if a > 7; /*...*/) yield /*...*/
这要求 monad 是一个 monad-with-zero (所以如果条件失败,你可以清空它)。
Either
不能明智地是一个带零的单子(除了Either[Unit,B]
,其中Left(())
可以是零)。
一种方法是说:好吧,好吧,只是不要那样使用你的理解。另一种方法是说:好吧,好吧,根本不用费心让 Either 成为一个 monad。Either
当然,这是个人喜好问题,但我可以看到,一旦您尝试使用所提供的全部功能,(在 Scala 中提供的常见 monad 中是独一无二的)就显得缺乏优雅for
。