This isn’t really an answer but wouldn’t fit in a comment. In this situation one should ask what infinite loop detection is and how it works. I’m going to explain it by converting from Haskell to a Haskell-look-alike language with strict (non lazy) evaluation (think eg JavaScript with Haskell syntax) and then explaining it.
Haskell:
let f () = f () in f ()
Convert to strict:
let f () = make_thunk (\() -> eval_thunk f ()) in eval_thunk (make_thunk (\() -> f ()))
Now let’s do an optimisation:
let f () = eval_thunk f_unit
f_unit = make_thunk (\() -> f ())
in
eval_thunk f_unit
Now let’s write down a fake definition for 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>>"
So we see that we get an infinite loop when we try to evaluate something as part of working out its value. You can trace the above program by hand to see how this error could arise.
But what if that optimisation hadn’t been made? Well then (assuming you don’t optimise to strictness) you would get a stack overflow and could report this as a <<loop>> error. If it were optimised to be truly strict then maybe you would get a stack overflow error or maybe you would get an infinite loop.
One might ask how to avoid this error and the answer could be:
- Don’t write infinite loops
- Maybe compile with no optimisations
But you say that sometimes infinite loops are useful because eg event loops or long lived servers. The reply is that in Haskell infinite loops are not useful because to be useful you need IO. Consider a function be_useful :: IO () and now one can write:
f = be_useful >>= \() -> f
And now there are two steps in doing f:
- Evaluating the thunk
- Doing the IO actions in that value
- Doing the next IO action (computing the thunk again) and so on.
This need not <<loop>>.
let f () = f () in f ()which is not detected by the black-holing mechanism. I don't know if there's an option to disable black-holing completely. Usually, it's a useful feature.mainof your program, or at the GHCi prompt. Can you elaborate about why do you want to disable black-holing?for (;;);at the end of a C program so that the terminal sticks around long enough for them to read the output when they run it in Windows. If this is what you're doing, there are better ways to go about it, in Haskell and in C.-threadedand run with+RTS -N2 -RTS? The threaded runtime generally handles blackholes differently (as greyholes) because some other thread could potentially be in the process of evaluating the thunk.