5

If I define

λ> data Bar = Bar Int deriving Show
λ> data Foo = Foo Bar deriving Show

and

λ> let foo = trace "foo" Foo (trace "bar" Bar 100)
λ> let two = trace "two" 2
λ> let g (Foo x)  y = y

then I think I understand why I get

λ> g foo two
foo
two
2

But if I then repeat this, I get

λ> g foo two
two
2

and I don't understand why foo appears not to have been evaluated for the second invocation of g, especially since it is clearly not (yet) somehow already available, as I can verify with

λ> foo
Foo bar
(Bar 100)

though — again, to my confusion — repeating the previous gives

λ> foo
Foo (Bar 100)

Why does my foo expression appear to be already evaluated in some cases, and not evaluated in others? And for that matter why does my two expression always need to be evaluated?

orome
  • 45,163
  • 57
  • 202
  • 418
  • 1
    `two` probably stays unevaluated because of its type, `(Num a) => a`. The literal `2` is secretly `fromInteger 2`, and the exact `fromInteger` function used depends on the type expected by the surrounding context. – melpomene Oct 11 '15 at 21:36
  • @melpomene: Interesting! That makes sense. – orome Oct 11 '15 at 21:39

2 Answers2

9

That's due to two's type. Lets check all the type's so far:

ghci> :t foo
foo :: Foo
ghci> :t two
two :: Num a => a

Aha! two is polymorphic. Therefore, its behaviour depends on the actual Num instance. Therefore, it needs to get re-evaluated in g. We can check this by using :sprint:

ghci> :sprint foo
foo = Foo _             -- simplified

Which indicates that we never looked at the contents of Foo. foo is in weak head normal form. This answers your second question. But back to your first. What happens on :sprint two?

ghci> :sprint two
two = _

As you can see, due to its polymorphic nature, two doesn't get to WHNF. After all, which WHNF should it take? You might want to use it as Integer, or Currency, or Complex Triple.

This is, by the way, a reason for the existence of the monomorphism restriction, see "A History of Haskell", section 6.2:

6.2 The monomorphism restriction

A major source of controversy in the early stages was the so-called “monomorphism restriction.” Suppose that genericLength has this overloaded type:

genericLength` :: Num a => [b] -> a

Now consider this definition:

f xs = (len, len)
  where
    len = genericLength xs

It looks as if len should be computed only once, but it can actually be computed twice. Why? Because we can infer the type len :: (Num a) => a; when desugared with the dictionary- passing translation, len becomes a function that is called once for each occurrence of len, each of which might used at a different type.

See also this Q&A for more information about the restriction.

That being said, we can easily change this if we fix two's type:

ghci> let foo = trace "foo" Foo (trace "bar" Bar 100)
ghci> let two = trace "two" (2 :: Integer)
ghci> let g (Foo x)  y = y

Now the output will be exactly as you've expected. Alternatively, you can enable the monomorphism restriction with :set -XMonomorphismRestriction, as it is disabled in current GHCi versions by default:

ghci> :set -XMonomorphismRestriction
ghci> let two = trace "two" 2
ghci> :t two
two :: Integer -- due to defaulting rules
Community
  • 1
  • 1
Zeta
  • 103,620
  • 13
  • 194
  • 236
  • That clears things up, except that the name is a but confusing, so just to be sure: With the restriction *disabled*, types like the that for the `two` example will *not* be inferred, and will thus remain polymorphic (so that they will be recomputed when a type is imposed). – orome Oct 12 '15 at 14:14
5
> :t foo
foo :: Foo
> :t two
two :: Num a => a

The second one is polymorphic, so it's a function in disguise! Every time you use it, you will evaluate a new trace call.

chi
  • 111,837
  • 3
  • 133
  • 218
  • Aha! And `foo` is "available" once it has been evaluated once (at the top level) — i.e., it doesn't need to be evaluated again (at least not as far as it already has been)? – orome Oct 11 '15 at 21:40
  • @raxacoricofallapatorius The "as far as it already has been" is exactly the important part in `foo's` case. You can check this with `:sprint`: `let k = map Bar [1..100]; length k; :sprint k` (replace the semicolons with enter during your GHCi session). – Zeta Oct 11 '15 at 21:53
  • @raxacoricofallapatorius Yes. Since it has a monomorphic type, and is bound at the top-level it will be evaluated once. Note that this is a choice of GHCi, not one mandated by the Haskell report. – chi Oct 11 '15 at 21:54