Search code examples
haskelllazy-evaluationghci

How are interruptions handled in GHCi?


I am experimenting with GHCi's :sprint command. Consider the following:

GHCi> xs = [1..10] :: [Int]
GHCi> :sprint xs
xs = _
GHCi> length xs
10
GHCi> :sprint xs
xs = [1,2,3,4,5,6,7,8,9,10]

This works as expected. What interested me is :sprint's behaviour after we interrupt some computation. Consider the following:

GHCi> xs = [1..] :: [Int]
GHCi> :sprint xs
xs = _
GHCi> length xs
Interrupted.
GHCi> :sprint xs

And it hangs.

The expected result was something like that (modulo the number of :s):

xs = _ : _ : _ : _

What causes :sprint ... to freeze? Why is there no access to information about the part of the list which was computed? It seems like a bug to me - there's no real reason to cast away all the work the interrupted length did. Is it a bug indeed, or am I wrong?


Solution

  • As @Daniel Wagner explained in the comments, GHCi actually behaves exactly as you expect. It seems to hang because length is extremely fast, and evaluates a huge number of elements, which takes :sprint some time to pretty-print to a string. Unlike ordinary GHCi output, :sprint forces it's string value before it starts printing. If you would wait long enough, :sprint would indeed print the partial string as expected.

    You can demonstrate this as follows:

    GHCi> xs = [1..100000] :: [Int]
    GHCi> :sprint xs
    xs = _
    GHCi> xs
    [1,2,3,4 ... 8504^CInterrupted.
    GHCi> :sprint xs
    1 : 2 : 3 : 4 : ... : 8504 : _