为什么这个Haskell代码不会终止?

时间:2011-10-31 22:30:08

标签: haskell

为什么以下Haskell代码不会终止:

foldr (||) True $ repeat False -- never terminates

当这样的事情发生时:

foldr (||) False $ repeat True -- => True

对我来说,这是第二个看起来更难以终止的表达方式。我对Haskell懒惰评估的看法有什么问题?

4 个答案:

答案 0 :(得分:18)

我认为你对懒惰的理解是正确的,但不适用于foldr。我们来看看它的“specification

foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)

然后看看你的表达

foldr (||) True $ repeat False -- never terminates

正如您所见,Truez)我们正在“寻找”让||终止,直到整个列表被消耗为止。这不会发生,因为列表是无限的。

这也应该解释实际终止的例子。

答案 1 :(得分:13)

第一个扩展为False || (False || (False || ...)),第二个扩展为True || (True || (True || ...))foldr的第二个参数是红色鲱鱼 - 它出现在||的最里面的应用程序中,而不是最外层的应用程序中,因此它实际上永远无法到达。

答案 2 :(得分:9)

如果您手动展开foldr

,问题就很明显了
foldr (||) True $ repeat False == False || (False || (False (False || ... True)))

因此,为了获得最终的False,代码必须评估列表直到其(不存在)结束。在第二个示例中,您重复True,因此可以进行短路评估。不要期待懒惰评价的魔法!

答案 3 :(得分:3)

另一个有用的见解是||在Haskell中不是可交换的,它是有偏见的

Prelude> undefined || True
*** Exception: Prelude.undefined
Prelude> True || undefined
True

与数学不同,||flip (||)是不同的功能。例如。比较

foldr (||) False $ repeat Truefoldr (flip (||)) False $ repeat True

前者终止,但后者不会。