我有兴趣知道为什么scala.Either
没有作为monad完成的设计决定。已经存在一些关于如何正偏置Either
的讨论,例如:
但是提到了太多的细节,我无法完整地了解为什么要这样做。有人可以概述一个有偏见的Either
的好处,关于这样做的问题,以及没有权利偏见的好处Either
(如果它们存在的话) ?
答案 0 :(得分:8)
我认为它归结为Principle of Least Astonishment。使用Either
编码成功或失败显然是人们所做的事情,但它不是Either
的唯一用途。事实上,没有太多理由让Right
取得成功,而Left
除了传统之外是失败的。正如阿德尔伯特的上述评论所提到的,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)
bar
中的Either
是失败案例,因此这就是结果,但想象一下Right
是.right
- 有偏见。上面的代码将在表达式中没有for (a <- foo(); b <- bar(a); c <- baz(b)) yield c
投影进行编译,如:
Either
如果你在代码中使用Left(1)
只是一个“一个或另一个”类型,你会惊讶于(1)这会编译和(2)它返回baz
似乎永远不会执行Validation
。
总之,如果您想使用Either
对成功或失败进行编码,请使用{{1}}。
答案 1 :(得分:5)
我不知道这是不是最初的原因,但至少有一个很好的理由。在Scala中,为了获得完整的功能,for
理解需要更多来自参数而不是它是monad。特别是,有像
for (a <- ma if a > 7; /*...*/) yield /*...*/
要求monad为monad-with-zero(如果条件失败,你可以将它清空)。
Either
明智地不能成为monad-with-zero(Either[Unit,B]
除外,其中Left(())
可以为零)。
一种方法是说:好的,好的,只是不要那样使用你的理解。另一种方法是说:好吧,好吧,不要打扰任何一个monad。当然,这是个人偏好的问题,但是我可以看到,Either
(Scala中提供的常见单子中唯一的一个)在你试图使用全部力量时,它的表面缺乏优雅。 {1}}给你。