Search code examples
haskelllazy-evaluation

Why does a data structure with strict fields not get evaluated to WHNF immediatly?


I've been learning about strict vs lazy data structures, and have been playing around with the :sprint command in ghci. My understanding of :sprint is it displays the evaluation status of selected variables. I've come across the following curiosity which I can't understand.

ghci> data Foo = Foo{i::Int,j::String}
ghci> data Bar = Bar{i:: !Int, j::String}
ghci> 
ghci> 
ghci> a = Foo (3+2) "abc"
ghci> b = Bar (3+2) "abc"
ghci> 
ghci> :sprint a
a = <Foo> _ _
ghci> :sprint b
b = _

My question is: why is a evaluated to WHNF by default, but b remains a thunk?

I was expecting the output of b to be b = <Bar> 5 _, which I can force by running seq b ().

ghci> seq a ()
()
ghci> seq b ()
()
ghci> :sprint a
a = <Foo> _ _
ghci> :sprint b
b = <Bar> 5 _

Solution

  • I believe it is because strict fields are just syntactic sugar, telling the compiler to automatically insert calls to seq in certain places.

    So the strictness annotation on Bar means that b = Bar (3+2) "abc" is actually compiled as something like b = let x = 3+2 in seq x (Bar x "abc").

    After a = Foo (3+2) "abc", a is a reference to an application of the constructor Foo; its fields contain thunks. Constructors are treated specially, so GHCi's :sprint can tell that the a refers to a constructor application and shows it as a = <Foo> _ _.

    But after b = Bar (3+2) "abc", b is a reference to an application of seq, not directly to an application of the constructor Bar. seq is just a function; it's special in terms of its implementation, but not in terms of being represented specially in memory the way constructors are. A reference to a (non-constructor) function application is just a thunk, so GHCi shows it as it would any other thunk: b = _.

    Forcing the thunk referred to by b would force the 3 + 2 and then result in a reference to an application of the Bar constructor. But binding a variable doesn't automatically force the expression that is assigned to it.