When I run something like:
Prelude> cycle "ab"
I can see an infinite printing of "ab". To stop it I just use Ctrl+c. And it works.
When I run:
Prelude Data.List> nub $ cycle "ab"
I am not able to stop it.
Question:
Update:
Ubuntu: version 18.10
GHCi: version 8.2.2
Quits GHCi. You can also quit by typing control-D at the prompt. Attempts to reload the current target set (see :load ) if any of the modules in the set, or any dependent module, has changed.
So the proper way to close haskell-shell is to hit Ctrl+D .
Prelude is a module that contains a small set of standard definitions and is included automatically into all Haskell modules.
Open a command window and navigate to the directory where you want to keep your Haskell source files. Run Haskell by typing ghci or ghci MyFile. hs. (The "i" in "GHCi" stands for "interactive", as opposed to compiling and producing an executable file.)
Great question! However, since How to abort execution in GHCI? already focuses on your second part, let's not repeat that here. Instead, let's focus on the first.
Why it so?
GHC optimizes loops aggressively. It optimizes them even further if there is no allocation that it's even a known bug:
19.2.1. Bugs in GHC
GHC’s runtime system implements cooperative multitasking, with context switching potentially occurring only when a program allocates. This means that programs that do not allocate may never context switch. This is especially true of programs using STM, which may deadlock after observing inconsistent state. See Trac #367 for further discussion. [emphasis mine]
If you are hit by this, you may want to compile the affected module with
-fno-omit-yields
(see -f*: platform-independent flags). This flag ensures that yield points are inserted at every function entrypoint (at the expense of a bit of performance).
If we check -fomit-yields
, we find:
-fomit-yields
Default: yield points enabled
Tells GHC to omit heap checks when no allocation is being performed. While this improves binary sizes by about 5%, it also means that threads run in tight non-allocating loops will not get preempted in a timely fashion. If it is important to always be able to interrupt such threads, you should turn this optimization off. Consider also recompiling all libraries with this optimization turned off, if you need to guarantee interruptibility. [emphasis mine]
nub $ cycle "ab"
is a tight, non-allocating loop, although last $ repeat 1
is an even more obvious non-allocating example.
The "yield points enabled" is misleading: -fomit-yields
is enabled by default. As the standard library is compiled with -fomit-yields
, all functions in the standard library that lead to tight, non-allocating loops may show that behaviour in GHCi, as you never recompile them.
We can verify that with the following program:
-- Test.hs
myLast :: [a] -> Maybe a
myLast [x] = Just x
myLast (_:xs) = myLast xs
myLast _ = Nothing
main = print $ myLast $ repeat 1
We can use C-c to quit it if we run it in GHCi without compiling beforehand:
$ ghci Test.hs
[1 of 1] Compiling Main ( Test.hs, interpreted )
Ok, one module loaded.
*Main> :main <pressing C-c after a while>
Interrupted.
If we compile it and then rerun it in GHCi, it will hang:
$ ghc Test.hs
[1 of 1] Compiling Main ( Test.hs, Test.o )
Linking Test.exe ...
$ ghci Test.hs
Ok, one module loaded.
*Main> :main
<hangs indefinitely>
Note that you need -dynamic
if you don't use Windows, as otherwise GHCi will recompile the source file. However, if we use -fno-omit-yield
, we suddenly can quit again (in Windows).
We can verify that again with another small snippet:
Prelude> last xs = case xs of [x] -> x ; (_:ys) -> last ys
Prelude> last $ repeat 1
^CInterrupted
As ghci
doesn't use any optimizations, it also doesn't use -fomit-yield
(and therefore has -fno-omit-yield
enabled). Our new variant of last
doesn't yield the same behaviour as Prelude.last
as it isn't compiled with fomit-yield
.
Now that we know why this happens, we know that we will experience that behaviour throughout the standard library, as the standard library is compiled with -fomit-yield
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With