5

我有一个关于haskell中单子的本体论问题;我对语言是否完全区分语句和表达式感到不安。例如,我觉得在大多数其他语言中,任何带有签名的东西a -> SomeMonadProbs ()都会被视为陈述。也就是说,由于 haskell 是纯函数式的,并且函数是由表达式组成的,所以我对 haskell 会根据表达式引擎对 monad 说些什么感到有点困惑。

4

3 回答 3

9

Monad只是与表达式交互的一个接口。例如,考虑使用do符号实现的列表推导:

example :: [(Int, Int)]
example = do
    x <- [1..3]
    y <- [4..6]
    return (x, y)

这意味着:

[1..3] >>= \x ->
[4..6] >>= \y ->
return (x, y)

...并代入(>>=)for 列表的定义给出:

concatMap (\x -> concatMap (\y -> [(x, y)]) [4..6]) [1..3]

重要的想法是,您可以使用do符号执行的任何操作都可以替换为对(>>=).

Haskell 中最接近“语句”的是do符号块的句法行,例如:

x <- [1..3]

这些行不对应于孤立的表达式,而是对应于非自包含表达式的句法片段:

[1..3] >>= \x -> ... {incomplete lambda}

所以说一切都是 Haskell 中的表达式真的更合适,do符号给你的东西看起来像一堆语句,但实际上是在底层的一堆表达式中去糖的。

于 2013-09-27T14:24:10.107 回答
7

这里有一些想法。

a >>= b是一个应用程序,就像任何其他应用程序一样,所以从句法的角度来看,Haskell 中显然没有语句,只有表达式。

从语义的角度来看(参见例如解决尴尬的小队论文),Haskell 语义有“指称”和“操作”片段。

指称片段>>=与数据构造函数类似,因此它被认为a >>= b是在 WHNF 中。“操作”片段“解构”了 IO monad 中的值,并在过程中执行不同的效果。

在推理程序时,您通常根本不需要考虑“操作”片段。例如,当您重构foo a >> foo alet bar = foo a in bar >> bar您不关心 的性质时foo,因此 IO 操作与此处的任何其他值没有区别。

这就是 Haskell 的闪光点,很容易说根本没有陈述,但它会导致有趣且有点自相矛盾的结论。例如,C预处理器语言可以被认为是C的一个指称片段。所以C也有指称片段和操作片段,但没有人说C是纯粹的函数式或没有语句。有关此问题的详细处理,请参阅The C language is pure functional post。

Haskell 当然在数量上与 C 不同:它的指称片段具有足够的表达力,可以在实际中使用,因此您必须比 C 更少地考虑其操作语义中的潜在转换。

但是当您必须考虑这些转换时,例如在推理写入网络套接字的数据顺序时,您必须诉诸于语句后语句的思维方式。

因此,虽然 IO 动作本身不是语句,并且在某种狭义的技术意义上根本没有语句,但动作代表语句,所以我认为可以公平地说语句以非常间接的形式出现在 Haskell 中。

于 2013-09-27T14:47:39.130 回答
5

语言是否完全区分语句和表达式

它不是。语法中没有“陈述”或类似的东西,在语言描述中没有任何东西被称为“陈述”或任何等价的东西(据我所知)。

语言报告将符号内的元素称为do“语句”。有两种不是表达式的语句:pat <- exp`` andlet decls`。

在大多数其他语言中,任何带有签名的东西a -> SomeMonadProbs ()都将被视为声明

Haskell 与大多数其他语言不同。这就是它的重点(显然,不是为了它而不同,而是将表达式和语句统一到一个结构中)。

于 2013-09-27T13:59:00.347 回答