8

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)?

Community
  • 1
  • 1
orome
  • 45,163
  • 57
  • 202
  • 418
  • 1
    By the way, there's no way at all to polymorphically (without a type class) evaluate a value beyond WHNF. – Reid Barton Oct 12 '15 at 15:58
  • @ReidBarton: Can you explain that a bit further (or is it [this](http://stackoverflow.com/a/33070412/656912))? – orome Oct 12 '15 at 16:16
  • 2
    It's not the same as in that link, it's just that without a type class, you have no way to get the information about how to access the subparts of a value of unknown type. (Hm, no high-level way, anyway - maybe there's some hideously unsafe way using the garbage collector's data) – Ørjan Johansen Oct 12 '15 at 16:54
  • @ØrjanJohansen: Is that relevant here, to `x`, for example? – orome Oct 12 '15 at 16:56
  • Not much, since clearly you *do* know `x`'s precise type. – Ørjan Johansen Oct 12 '15 at 17:08
  • @ØrjanJohansen: Good, I was confused about why it had been brought up in this context. – orome Oct 12 '15 at 17:10
  • 3
    @raxacoricofallapatorius Presumably it had been brought up as a general statement of which one specialization is that `evaluate` -- which accepts a fully polymorphic argument -- does not evaluate a value beyond WHNF. – Daniel Wagner Oct 12 '15 at 17:11
  • Whereas [NFData](http://hackage.haskell.org/package/deepseq-1.4.1.2/docs/Control-DeepSeq.html#t:NFData) enables you to fully evaluate a value to normal form (as long as the instance follows the rules). – Zeta Oct 12 '15 at 17:18
  • Right, what @DanielWagner said. It's an answer to the question in the title. Not just `evaluate`, but *any* function of the same type `a -> IO a` can evaluate its argument no further than to WHNF. – Reid Barton Oct 12 '15 at 17:35

1 Answers1

15

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
Ørjan Johansen
  • 18,119
  • 3
  • 43
  • 53
  • Perfect! As soon as I posted I wondered about this, but I'm still vague enough on IO actions and how they work (especially when they are "embedded" as they are in interactions with GHCi) that I couldn't quite nail it down. – orome Oct 12 '15 at 16:25