如果我的程序出现无限循环,我希望它实际上被卡住:无限执行、耗尽内存或因堆栈溢出而崩溃。
我不想立即退出并显示<>错误消息。如何禁用运行时的无限循环检测?
我不想立即退出并显示<>错误消息。如何禁用运行时的无限循环检测?
假设您有一个Haskell程序:
-- Loop.hs
foo :: Int
foo = foo
main = print $ foo
$ ghc -O2 Loop.hs
如果你运行它,它会生成一个Loop: <<loop>>
错误。
但是,如果你创建一个汇编文件:
# halt_and_catch_fire.s
# version for Linux x86_64 only
.globl base_ControlziExceptionziBase_nonTermination_closure
.section .data
.align 8
base_ControlziExceptionziBase_nonTermination_closure:
.quad loop
.section .text
.align 8
.quad 0
.quad 14 # FUN_STATIC
loop: jmp loop
然后使用适当的链接器标志将其与您的Haskell程序编译在一起(以忽略重复定义):
$ ghc -O2 Loop.hs halt_and_catch_fire.s -optl -zmuldefs
let f () = f () in f ()
转换为严格模式:
let f () = make_thunk (\() -> eval_thunk f ()) in eval_thunk (make_thunk (\() -> f ()))
let f () = eval_thunk f_unit
f_unit = make_thunk (\() -> f ())
in
eval_thunk f_unit
现在,让我们写一个假定义来解释“thunks”:
data ThunkInner a = Done a | Fresh (() -> a) | Working
data Thunk a = Thunk { mutable inner :: ThunkInner a }
make_thunk f = Thunk (Fresh f)
eval_thunk t = case t.inner of
| Done a -> a
| Fresh f -> (t.inner <- Working; let result = f () in t.inner <- Done result; result)
| Working -> error "<<loop>>"
IO
。考虑一个函数be_useful :: IO ()
,现在我们可以写成:f = be_useful >>= \() -> f
现在执行f
有两个步骤:
这不需要<<loop>>
。
let f () = f () in f ()
这个方法就不会被黑洞机制检测到。我不知道是否有选项可以完全禁用黑洞机制。通常,它是一个有用的功能。 - chifor (;;);
,以便在Windows上运行时终端保持足够长的时间让他们读取输出。如果您正在做这件事,那么在 Haskell 和 C 中有更好的方法。 - DarthFennec-threaded
编译并使用+RTS -N2 -RTS
运行,会发生什么?线程化运行时通常以不同的方式处理黑洞(作为灰洞),因为其他线程可能正在评估该thunk。 - dfeuer