<<loop>>错误"work"详细怎么说?

How does the <<loop>> error "work" in detail?

我正在开发这个工具,用户可以在其中定义并包含在[配置文件 |内容文本文件 | etc] 他们自己的 "templates" (比如小胡子等),这些可以引用其他人所以他们可以引发循环。就在我正要创建一个 "max-loops" 设置时,我用 runghc 意识到该程序在一段时间后退出并带有 <<loop>> 的告别消息。这对我来说实际上已经足够好了,但引发了一些思考:

所有的东西我当然可以用困难的方式弄清楚,但谁知道也许有人已经更详细地研究过这个..(很难 google/ddg 因为 "haskell" "<<loop>>" 因为他们去掉了角度括号,然后显示 "how to loop in Haskell" 等的结果。)

这是在 GHC 中实现的 STG 运行时的简单 "improvement"。我会分享我的理解,但 GHC 专家可能会提供更有用和准确的信息。

GHC 在进行了多次优化后编译为一种称为 Core 的中间语言。您可以使用 ghc -ddump-simpl ...

查看它

非常粗略地说,在 Core 中,未计算的绑定(如 let x = 1+y+x in f x)会创建一个 thunk。在某处分配了一些内存来表示闭包,并使 x 指向它。

当(并且如果)xf 强制执行时,thunk 被评估。这是改进:在计算开始之前,x 的 thunk 被一个名为 BLACKHOLE 的特殊值覆盖。在 x 被评估(对 WHNF)之后,黑洞再次被实际值覆盖(因此我们不会重新计算它,例如 f x = x+x)。

如果黑洞曾经被强制触发,<<loop>>就会被触发。这实际上是一个 IO 异常(那些也可以在纯代码中引发,所以这很好)。

示例:

let x = 1+x in 2*x          -- <<loop>>
let g x = g (x+1) in  g 0   -- diverges
let h x = h (10-x) in h 0   -- diverges, even if h 0 -> h 10 -> h 0 -> ...
let g0 = g10 ; g10 = g0 in g0   -- <<loop>>

请注意,h 0 的每次调用都被认为是一个不同的 thunk,因此没有黑洞被强制在那里。

棘手的部分是了解哪些 thunk 实际上是在 Core 中创建的并不是完全微不足道的,因为 GHC 可以在发出 Core 之前执行多项优化。因此,我们应该将 <<loop>> 视为奖励,而不是 GHC 的给定/硬性保证。未来的新优化可能会用实际的非终止替换一些 <<loop>>

如果你想google一些东西,"GHC, blackhole, STG"应该是很好的关键字。