haskell 为什么我们需要可能单子而不是任一单子

roejwanj  于 2022-11-14  发布在  其他
关注(0)|答案(3)|浏览(160)

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

c0vxltue

c0vxltue1#

当然,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,而不是“传统上预期的”简单情况(这是一个主观观点,但是如果您获得经验,这基本上是可以的)。

hs1ihplo

hs1ihplo2#

@phg的答案很棒。我会在学习它们的时候补充一些帮助我澄清这一点的东西:

  • Maybe是1(值)或无-即,有值或无值
  • Either是一个逻辑析取,但你总是至少有一个(值)-即,你有一个 * 或 * 另一个,但不是两个都有。

Maybe非常适合于你可能有值或者没有值的地方--例如在列表中查找一个项目。如果列表包含它,我们得到(Just x),否则我们得到Nothing
Either是代码中分支的完美表示--它将以某种方式运行; LeftRight。我们使用助记符来记住它:Right是 * 正确 正确 *)的方式; Leftwrong way(错误)。当然这不是它唯一的用法,但绝对是最常见的用法。
我知道这些差异一开始看起来很微妙,但实际上它们适用于非常不同的事情。

83qze16e

83qze16e3#

你看,我们可以把这一点放到极端,所有的乘积类型都可以用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

相关问题