为什么我们需要 Maybe Monad 而不是 Either Monad

Why Do We Need Maybe Monad Over Either Monad

我在玩 Maybe 和 Either monad 类型(链接,根据返回值应用条件函数,还返回链接函数失败的错误消息等)。所以在我看来,我们可以通过使用 Either monad 来实现 Maybe 所做的相同和更多的事情。所以我的问题是它们之间的实际或概念差异在哪里?

Maybe aEither Unit a 同构,你当然是对的。问题是它们通常在语义上用于表示不同的事物,有点像返回 null 和抛出 NoSuchElementException 之间的区别:

  • Nothing/None表示"expected"缺少某物,而
  • Left e表示获取错误,无论什么原因。

也就是说,我们甚至可以将两者结合起来,例如:

query :: Either DBError (Maybe String)

我们表达缺失值(数据库 NULL)和连接错误、DBMS 或其他任何错误的可能性(不是说没有更好的设计,但你得到点)。

有时候,边界是流动的;对于 saveHead :: [a] -> Maybe a,我们可以说错误的预期可能性被编码在函数的意图中,而像 saveDivide 这样的东西可能被编码为 Float -> Float -> Either FPError FloatFloat -> Float -> Maybe Float,取决于用例(同样,只是一些愚蠢的例子......)。

如果有疑问,最好的选择可能是使用带有语义编码的自定义结果 ADT(如 data QueryResult = Success String | Null | Failure DBError),并且更喜欢 Maybe 而不是 "traditionally expected" 的简单情况](一个主观点,但是如果您获得经验,这将是基本可以的)。

@phg 的回答很棒。当我学习它们时,我会插话帮助我理清头绪:

  • Maybe 是一个(值)或 none – 即,你有一个值,或者你什么都没有
  • Either 是一个逻辑析取,但您始终至少有一个(值)- 即,您有一个 另一个,但不能同时有两个。

Maybe 非常适合您可能有或没有价值的事情 - 例如在列表中查找项目。如果列表包含它,我们得到 (Maybe x) 否则我们得到 Nothing

Either 是您代码中分支的完美表示 - 它会以一种方式或另一种方式进行; LeftRight。我们用一个助记符来记:Right就是正确)的方式; Left 错误的 方式(错误)。这当然不是唯一的用途,但绝对是最常见的。

我知道这些差异起初可能看起来很微妙,但实际上它们适用于非常不同的事物。

好吧,你看,我们可以说所有产品类型都可以只用 2 元组表示,所有非递归和类型都可以用 Either 来表示。为了额外表示递归类型,我们需要一个定点类型。

例如,当我们也可以写 (a, (b, (c,d)))(((a,b), c), d) 时,为什么要有 4 元组 (a,b,c,d)

或者为什么要有列表,当以下内容也适用时?

data Y f = Y (f (Y f))

type List a = Y ((,) (Either () a))


nil = Y (Left (), undefined)

cons a as = Y (Right a, as)

infixr 4 cons

numbers = 1 `cons` 2 `cons` 3 `cons` nil

-- this is like foldl

reduce f z (Y (Left (), _)) = z
reduce f z (Y (Right x, xs)) = reduce f (f z x) xs


total = reduce (+) 0 numbers