haskelllazy-evaluationdenotational-semantics

Does Haskell's 'evaluate' reduce to normal or WHNF?


I understand (I think) that Haskell's seq, will (generally) reduce its first argument to WHNF, and see this behavior as expected in GHCi:

λ> let x = (trace "foo" Foo (trace "bar" Bar 100)) in seq x 0
foo
0

However, though the documentation for evaluate says that it also reduces its argument to WHNF, it looks like it actually fully reduces its argument to normal form:

λ> let x = (trace "foo" Foo (trace "bar" Bar 100)) in evaluate x
foo
Foo bar
(Bar 100)

I can confirm this (apparent) discrepancy with

λ> let y = (trace "foo" Foo (trace "bar" Bar 100))
λ> seq y 0
foo
0
λ> :sprint y
y = <Foo> _

and

λ> let z = (trace "foo" Foo (trace "bar" Bar 100))
λ> evaluate z
foo
Foo bar
(Bar 100)
λ> :sprint z
z = <Foo> (<Bar> 100)

If the documentation for evaluate is correct, shouldn't the behavior of seq and evaluate be the same? What am I missing here (as a Haskell beginner)?


Solution

  • What you are missing is that GHCi also prints the result of IO actions (if they can be shown and are not ()), which does cause it to evaluate to normal form. Try instead:

    λ> let x = (trace "foo" Foo (trace "bar" Bar 100)) in evaluate x >> return ()
    foo