I am not able to explain the following behavior:
Prelude> let x = 1 + 2
Prelude> let y = (x,x)
Prelude> :sprint y
Prelude> y = _
Now when I specify a type for x:
Prelude> let x = 1 + 2 ::Int
Prelude> let y = (x,x)
Prelude> :sprint y
Prelude> y = (_,_)
Why does the specification of x's type force y to its weak head normal form (WHNF)?
I accidentally discovered this behavior while reading Simon Marlow's Parallel and Concurrent Programming In Haskell.
Here's an informed guess. In your first example,
x :: Num a => a
So
y :: Num a => (a, a)
In GHC core, this y
is a function that takes a Num
dictionary and gives a pair. If you were to evaluate y
, then GHCi would default it for you and apply the Integer
dictionary. But from what you've shown, it seems likely that doesn't happen with sprint
. Thus you don't yet have a pair; you have a function that produces one.
When you specialize to Int
, the dictionary is applied to x
, so you get
x :: Int
y :: (Int, Int)
Instead of a function from a dictionary, x
is now a thunk. Now no dictionary needs to be applied to evaluate y
! y
is just the application of the pair constructor to two pointers to the x
thunk. Applying a constructor doesn't count as computation, so it's never delayed lazily.