为什么Scalas不是monad?

时间:2012-09-05 22:51:34

标签: scala

我有兴趣知道为什么scala.Either没有作为monad完成的设计决定。已经存在一些关于如何正偏置Either的讨论,例如:

但是提到了太多的细节,我无法完整地了解为什么要这样做。有人可以概述一个有偏见的Either的好处,关于这样做的问题,以及没有权利偏见的好处Either(如果它们存在的话) ?

2 个答案:

答案 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}}给你。