我正在玩Maybe和Either monad类型(链接,根据返回值应用条件函数,还返回链接函数失败的错误消息等)。所以我觉得我们可以通过使用Either monad来实现相同和更多的事情。所以我的问题是那些之间的实际或概念上的区别?
答案 0 :(得分:12)
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 Float
或Float -> Float -> Maybe Float
,取决于用例(再次,只是一些愚蠢的例子......)。
如果有疑问,最好的选择可能是使用具有语义编码的自定义结果ADT(如data QueryResult = Success String | Null | Failure DBError
),并且更喜欢Maybe
到“传统上预期”的简单情况(a主观点,但如果你获得经验,那将是最好的。)
答案 1 :(得分:7)
@ phg的答案很棒。在我学习它的时候,我会帮助为我清理它的东西:
Maybe
是一个(值)或没有 - 也就是说,你有一个值或者什么都没有Either
是一个逻辑分离,但你总是至少有一个(值) - 即你有一个或另一个,但不是两个。 Maybe
非常适合您可能有或没有价值的地方 - 例如在列表中查找项目。如果列表包含它,我们得到(Maybe x)
,否则我们得到Nothing
Either
是代码中分支的完美表示 - 它将以某种方式运行; Left
或Right
。我们使用助记符来记住它: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