如何<loop>详细"work"<>错误?



我正在开发这个工具,用户可以在[config files|content-text files|etc]中定义并包含自己的"模板"(如胡子等),这些模板可以引用其他模板,从而引发循环。就在我准备创建一个"最大循环"设置时,我意识到用runghc程序过了一会儿就退出了,只显示了<<loop>>的告别消息。这对我来说已经足够好了,但也引发了一些思考:

  • GHC或运行时如何实际检测到它卡在循环中,以及如何区分所需的长时间运行操作和意外的无限循环?停顿的问题仍然是我上次检查的问题。。

  • 是否有任何(时间或迭代)限制可以自定义设置为编译器或运行时?

  • 这是仅runghc-还是存在于所有最终编译输出中?

  • 当构建版本禁用这种明显的内置循环检测时,会在很久以后设置任何-o(优化)标志吗?

当然,所有的事情我都很难弄清楚,但谁知道呢,也许有人已经对此进行了更详细的研究。。("haskell" "<<loop>>"很难在谷歌/ddg上搜索,因为它们去掉了尖括号,然后显示"如何在Haskell中循环"等的结果。)

这是在GHC中实现的STG运行时的一个简单"改进"。我会分享我所了解的,但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>>

如果你想在谷歌上搜索一些东西,"GHC,黑洞,STG"应该是不错的关键词。

相关内容

  • 没有找到相关文章

最新更新