我开始了我的 Grand Haskell Crusade (GHC:)),我对 monad 和 IO 函数有点困惑。谁能简单解释一下这两个函数有什么区别?
f1 = do x <- [1,2]
[x, x+1] -- this is monad, right?
f2 = do x <- [1,2]
return [x, x+1]
结果是:
*Main> f1
[1,2,2,3]
*Main> f2
[[1,2],[2,3]]
最佳答案
要了解为什么会得到特定的答案,脱糖解释非常有帮助。让我用一些关于培养 Haskell 代码认知的一般性建议来补充它们。
Haskell 的类型系统不区分两个可分离的“道德”目的:
[x]
值的类型,它是包含从x
中提取的元素的列表[x]
x
元素的计算类型,允许优先选择
这两个概念具有相同的表示形式并不意味着它们发挥相同的作用。在f1
中,[x, x+1]
扮演着计算的角色,因此它生成的可能性被合并到整个计算生成的选择中:这就是列表 monad 的 >>=
会执行此操作。然而,在 f2
中,[x, x+1]
扮演的是值的角色,因此整个计算会在两个值之间生成优先级选择(这恰好是是列表值)。
Haskell 不使用类型来进行这种区分[你现在可能已经猜到我认为应该这样做,但那是另一个故事了]。相反,它使用语法。所以你需要训练你的大脑在阅读代码时感知值(value)和计算角色。 do
表示法是用于构造计算的特殊语法。 do
中的内容是根据以下模板套件构建的:
三个蓝色部分进行do
计算。我将计算孔标记为蓝色,将值孔标记为红色。这并不意味着是一个完整的语法,只是一个如何在你的头脑中感知代码片段的指南。
事实上,您可以在蓝色位置编写任何旧表达式,前提是它具有适当的单子(monad)类型,并且如此生成的计算将根据需要使用 >>=
合并到整体计算中。在您的 f1
示例中,您的列表位于蓝色位置,并被视为优先选择。
类似地,您可以在红色位置编写表达式,这些表达式很可能具有一元类型(如本例中的列表),但它们仍然会被视为值。这就是 f2
中发生的情况:结果的外括号是蓝色的,但内括号是红色的。
训练你的大脑在阅读代码时将值/计算分开,这样你就能本能地知道文本的哪些部分在做什么工作。一旦你重新编程了你的大脑,f1
和 f2
之间的区别看起来就完全正常了!
关于list - 在列表 monad 中使用 return 与不使用 return,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11323300/