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

时间:2017-03-02 11:34:20

标签: haskell functional-programming monads maybe either

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

3 个答案:

答案 0 :(得分:12)

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

  • Nothing / None表示某些内容的“预期”缺失,而
  • 无论出于何种原因,
  • Left e表示获取错误。

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

query :: Either DBError (Maybe String)

我们表示缺少值的可能性(DB NULL)和连接中的错误,DBMS或其他(不是说没有更好的设计,但你明白了)。

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

如果有疑问,最好的选择可能是使用具有语义编码的自定义结果ADT(如data QueryResult = Success String | Null | Failure DBError),并且更喜欢Maybe到“传统上预期”的简单情况(a主观点,但如果你获得经验,那将是最好的。)

答案 1 :(得分:7)

@ phg的答案很棒。在我学习它的时候,我会帮助为我清理它的东西:

  • Maybe是一个(值)或没有 - 也就是说,你有一个值或者什么都没有
  • Either是一个逻辑分离,但你总是至少有一个(值) - 即你有一个另一个,但不是两个。

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

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

我知道这些差异一开始可能看起来很微妙,但实际上它们适用于非常不同的东西。

答案 2 :(得分:1)

嗯,你知道,我们可以通过说Either所有产品类型只能由2元组和所有非递归和类型来表示。为了另外表示递归类型,我们需要一个修复点类型。

例如,为什么我们可以写(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