Loops “好奇如何”;loop=loop";在Haskell中进行评估
我以为这样的表达式会让Haskell永远计算。但GHCi和编译程序中的行为令我惊讶 例如,在GHCi中,这些表达式一直阻塞到ILoops “好奇如何”;loop=loop";在Haskell中进行评估,loops,haskell,recursion,evaluation,infinite-loop,Loops,Haskell,Recursion,Evaluation,Infinite Loop,我以为这样的表达式会让Haskell永远计算。但GHCi和编译程序中的行为令我惊讶 例如,在GHCi中,这些表达式一直阻塞到IControl+C,但不消耗CPU。看起来它在睡觉 let loop = loop let loop = 1 + loop 我尝试用GHC编译这些程序: main = print loop where loop = 1 + loop main = print loop where loop = if True then loop else 1 印刷的是: M
Control+C
,但不消耗CPU。看起来它在睡觉
let loop = loop
let loop = 1 + loop
我尝试用GHC编译这些程序:
main = print loop
where loop = 1 + loop
main = print loop
where loop = if True then loop else 1
印刷的是:
Main: <<loop>>
Main:
所以我的问题是:显然,这些表达式被编译成不同于命令式语言中的循环或递归调用。它们被编译成什么?这是一个特殊的规则来处理0-arg函数,它们自己在右边,还是一个更一般的特殊情况,我不知道
[编辑]:
还有一个问题:如果这恰好是编译器的特殊处理,那么在无法检查所有无限循环的情况下执行此操作的原因是什么熟悉的“语言”不关心像while(true)这样的情况
或intf(){return f();}
,对吗
非常感谢。在某些有限的情况下,编译器可以在其其他控制流分析中确定是否存在这样的循环,并在此时使用引发适当异常的代码替换循环项。当然,这不是在所有情况下都能做到的,但只有在一些更明显的情况下才能做到,在这些情况下,编译器正在做的其他工作自然会导致这种情况 至于为什么Haskell比其他语言更经常发现这一点:
- 这些情况不会发生在像C这样严格的语言中。当惰性变量的计算依赖于它自己的值时,这些循环就会发生
- 像C这样的语言在循环中有非常特殊的语义;也就是说,按什么顺序做什么。因此,他们被迫实际执行循环。但是,Haskell定义了一个特殊的值
(“底部”),用于表示错误的值。严格要求自身的值(即,它们依赖于自己的值进行计算)是124;
。124;
上的模式匹配结果可以是无限循环,也可以是异常;您的编译器在这里选择后者
- Haskell编译器对执行严格性分析非常感兴趣,即证明某个表达式依赖于某些其他表达式,以便执行某些优化。这种循环分析作为严格度分析器中的一种边缘情况自然出现,必须以某种方式进行处理
有关当前黑洞实现的超级极客技术细节,请参阅最近Haskell Implementors研讨会上Simon Marlow的演讲,“在多核上安排惰性评估”。感谢bdonlan。我只是更新了一下我的问题。那么,试图检测无限循环背后的原因是什么?为什么在编译时没有警告的情况下运行时会出现异常?用错误替换这些东西的常用术语是“黑洞”。此外,例如cf,它基本上做了相同的事情。虽然GHC可能确实检测到简单的
let loop=loop in…
构造,但问题中的示例实际上不是使用“其他控制流分析”检测到的,而是在运行时通过“blackholing”机制检测到的。