Haskell 为什么我们需要单子而不是单子
我在玩Maybe和monad类型(链接,根据返回值应用条件函数,还返回错误消息链接函数失败等等)。所以在我看来,我们可以通过使用任何一个单子来实现相同的和更多的事情。所以我的问题是,它们之间的实际或概念上的区别在哪里?你当然是对的,Haskell 为什么我们需要单子而不是单子,haskell,functional-programming,monads,maybe,either,Haskell,Functional Programming,Monads,Maybe,Either,我在玩Maybe和monad类型(链接,根据返回值应用条件函数,还返回错误消息链接函数失败等等)。所以在我看来,我们可以通过使用任何一个单子来实现相同的和更多的事情。所以我的问题是,它们之间的实际或概念上的区别在哪里?你当然是对的,可能a与任一单元a同构。问题是,它们通常在语义上用于表示不同的事物,有点像返回null和抛出NoSuchElementException之间的区别: Nothing/None表示“预期的”缺失,而 Left e表示由于任何原因在获取它时出错 也就是说,我们甚至可以
可能a
与任一单元a
同构。问题是,它们通常在语义上用于表示不同的事物,有点像返回null
和抛出NoSuchElementException
之间的区别:
/Nothing
表示“预期的”缺失,而None
表示由于任何原因在获取它时出错Left e
query :: Either DBError (Maybe String)
其中,我们表示了缺失值(DBNULL
)和连接、数据库管理系统或其他方面的错误的可能性(不是说没有更好的设计,但你明白了)
有时,边界是流动的;对于saveHead::[a]>可能是一个
,我们可以说错误的预期可能性是按照函数的意图编码的,而类似于saveDivide
的东西可能被编码为Float->Float->FPError Float
或Float->Maybe Float
,具体取决于用例(同样,只是一些愚蠢的例子…)
如果有疑问,最好的选择可能是使用带有语义编码的自定义结果ADT(如
data QueryResult=Success String | Null | Failure DBError
),并且更喜欢Maybe
,而不是“传统预期”的简单情况(这是一个主观点,但如果您获得了经验,这基本上是可以的).@phg的答案很好。我会在学习它们的时候提出一些帮助我澄清问题的建议:
是一(值)或无–即,你有值或你什么都没有可能
是一个逻辑析取,但您总是至少有一个(值)-即,您有一个或另一个,但不是两个都有或者
可能
适用于您可能有价值或可能没有价值的情况,例如在列表中查找某个项目。如果列表中包含该项目,我们会得到(可能是x)
,否则我们会得到什么都没有
或者
是代码中分支的完美表示-它会朝一个方向或者另一个方向移动;左
或者右
。我们使用助记符来记住它:右
是正确的方式;左
是错误的方式(错误).这当然不是唯一的用途,但肯定是最常见的
我知道这些差异一开始可能看起来很微妙,但实际上它们适用于非常不同的事物。好吧,你看,我们可以说,所有产品类型都可以用2元组表示,所有非递归和类型都可以用
表示。为了另外表示递归类型,我们需要一个不动点t类型
例如,当我们可以编写(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
我很惊讶这不是一个骗局。好问题。提到逻辑析取,你得到了+1。对于FP新手来说,这是一个非常平易近人的答案。谢谢Jared。你的反馈对我来说意义重大^_^