21
Prelude> let a = 3
Prelude> :sprint a
a = _
Prelude> let c = "ab"
Prelude> :sprint c
c = _

Why does it always print a _? I don't quite get the semantics of the :sprint command.

Erik Kaplun
  • 37,128
  • 15
  • 99
  • 111
vik santata
  • 2,989
  • 8
  • 30
  • 52
  • try `seq c ()` after: `:sprint c` will give you `c = 'a' : _` ... also read the link I posted in your last question – Random Dev Feb 04 '16 at 10:23

3 Answers3

17

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.

MathematicalOrchid
  • 61,854
  • 19
  • 123
  • 220
  • 29
    Remark: Since `[1..]` has a polymorphic type, it's likely that `:sp xs` yields `_`, even after `head xs`. `let xs = [1..] :: [Integer]` will fix this. – Zeta Jul 18 '16 at 16:31
16

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]
Nicolas Mattia
  • 1,269
  • 11
  • 20
  • 4
    Note that this only applies to "overloaded" values like `xs`; things that are have a type with variables and have type class constraints on those variables. It's mostly only examples involving literal numbers that behave this way; unfortunately numbers are the obvious things to play around with while learning. If you instead play around with booleans (`True`, `False`, `&&`, `and`, etc) then everything mostly behaves the same regardless of `NoMonomorphismRestriction` or whether you give an explicit type signature. – Ben Mar 05 '17 at 00:18
7

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
Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • 11
    for `let a = 3` it's more complicated (you should try this) - by default `a` will be `a :: Num a => a` and in your case will always `:sprint` to `_` - IMO the `String` example is better suited to get a feeling for this – Random Dev Feb 04 '16 at 10:30
  • 8
    if you use `let a = 3`, you better specify a type `let a = 3 :: Int` so you won't get confused, also note this behaviour has changed in GHC 7.8 in older versions you did not have to write the type in this statement to make `:sprint` work as 'expected'. – epsilonhalbe Feb 04 '16 at 13:23