为什么MCHaskell函数会导致栈溢出

Why does MC Haskell function result in stack overflow

我正在学习 Haskell 这本书的第 8 章。在做练习时,我注意到一些我不明白的地方。

为什么会导致堆栈溢出

mc x | x>100 = x-10
     | otherwise = mc $ mc x+11

但这不是

mc x | x>100 = x-10
     | otherwise = mc $ mc (x+11)

我认为这与 x+11 在第一个示例中未被计算有关,但不是总是计算这样的表达式

例如

Prelude> id 43+94
137

第一个表达式

mc $ mc x+11

被解释为

mc ((mc x) + 11)

因为函数应用优先于运算符。

第二个表达式

mc $ mc (x+11)

解释为:

mc (mc (x+11))

第一个确实永远不会被评估,因为如果你写:

<b>mc x</b> | x > 100 = x-10
     | otherwise = mc (<b>(mc x)</b> + 11)

然后你根据mc x定义mc x。除非该表达式中的 mc x 未被计算,因此您将在计算 mc x 时调用 mc x,因此它将继续调用。

这纯粹是关于运算符优先级的。特别是,函数应用程序优先于所有运算符。所以这个:

mc x+11

实际解析为

(mc x)+11

以及您尝试 "visually" 指示所需分组的间距或缺少间距的事实没有任何区别。这当然是你的第二个版本效果更好的原因,因为你明确指出了你想要的分组。

当然,无意的解释意味着,对于 x <= 100,为了计算 mc x,编译器必须首先计算 mc x,依此类推。因此最终的堆栈溢出。