2017-03-02 53 views
11

我在玩Maybe和Monad类型(Chaining,根据返回值应用条件函数,还返回链接函数失败等错误消息)。所以它对我来说似乎就像我们可以通过使用任一monad实现同样的和更多的事情。所以我的问题是这些之间的实际或概念差异?为什么我们需要可能Monad在任一Monad

+0

我很震惊,这不是一个骗局。很好的问题。 –

回答

10

你当然是对的,Maybe a是同构于Either 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来处理“传统期望”的简单情况(主观点,但是大多数都可以,如果你获得经验)。

5

@ phg的回答非常好。我会附和东西清除了起来,让我当我学习他们:

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

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

Either是在你的代码分支的完美表现 - 它会去一个或其他方式; LeftRight。我们使用助记符来记住它:Right正确)的方式; Left错误方式(错误)。这当然不是,而是最常见的。

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

+1

对于提及逻辑析取,你可以得到+1。这对于新来FP的人来说是非常平易近人的答案。 –

+0

谢谢Jared。您的反馈意味着我很多^ _ ^ – naomik

1

嗯,你看,我们可以把这个说得极端,说所有的产品类型都可以用2元组和所有的非递归和类型来表示,由Either。为了额外表示递归类型,我们需要一个fixpoint类型。

例如,为什么有4元组(a,b,c,d)时我们还可以写(a, (b, (c,d)))(((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