Prelude> let a = 3
Prelude> :sprint a
a = _
Prelude> let c = \"ab\"
Prelude> :sprint c
c = _
Why does it always print a _
?
I'm a bit late, but I had a similar issue:
λ: let xs = [1,2,3]
xs :: Num t => [t]
λ: :sprint xs
xs = _
λ: print xs
λ: :sprint xs
xs = _
This issue is specific to polymorphic values. If you have -XNoMonomorphismRestriction
enabled ghci will never really evaluate/force xs
, it'll only evaluate/force specializations:
λ: :set -XMonomorphismRestriction
λ: let xs = [1,2,3]
xs :: [Integer]
λ: print xs
λ: :sprint xs
xs = [1,2,3]
Haskell is lazy. It doesn't evaluate things until they are needed.
The GHCi sprint
command (not part of Haskell, just a debugging command of the interpreter) prints the value of an expression without forcing evaluation.
When you write
let a = 3
you bind a new name a
to the right-hand side expression, but Haskell won't evaluate that thing yet. Therefore, when you sprint
it, it prints _
as the value to indicate that the expression has not yet been evaluated.
Try this:
let a = 3
:sprint a -- a has not been evaluated yet
print a -- forces evaluation of a
:sprint a -- now a has been evaluated
Haskell is a lazy language. It doesn't evaluate results until they are "needed".
Now, just printing a value causes all of it to be "needed". In other words, if you type an expression in GHCi, it will try to print out the result, which causes it all to be evaluated. Usually that's what you want.
The sprint
command (which is a GHCi feature, not part of the Haskell language) allows you to see how much of a value has been evaluated at this point.
For example:
Prelude> let xs = [1..]
Prelude> :sprint xs
xs = _
So, we just declared xs
, and it's currently unevaluated. Now let's print out the first element:
Prelude> head xs
1
Prelude> :sprint xs
xs = 1 : _
Now GHCi has evaluated the head of the list, but nothing more.
Prelude> take 10 xs
[1,2,3,4,5,6,7,8,9,10]
Prelude> :sprint xs
xs = 1 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10 : _
Now the first 10 elements are evaluated, but more remain. (Since xs
is an infinite list, that's not surprising.)
You can construct other expressions and evaluate them a bit at a time to see what's going on. This is really part of the GHCi debugger, which lets you step through your code one bit at a time. Especially if your code is getting caught in an infinite loop, you don't want to print
anything, because that might lock up GHCi. But you still want to see what's going on... hence sprint
, which lets you see what's evaluated so far.