0

Given:

λ: let x = 1 + 2

I run sprint to print its value:

λ: :sprint x
x = _

As expected, it's unevaluated.

But, after evaluating x:

λ: x
3

sprint still outputs _, i.e. unevaluated:

λ: :sprint x
x = _

Why is that?

Cactus
  • 27,075
  • 9
  • 69
  • 149
Kevin Meredith
  • 41,036
  • 63
  • 209
  • 384

1 Answers1

3

It's because x is polymorphic.

Compare with:

Prelude> let x = 1 + 2 :: Int
Prelude> :sprint x
x = _
Prelude> x
3
Prelude> :sprint x
x = 3
Prelude>

When x is polymorphic GHCI cannot replace the thunk with a specific value since you might evaluate it later as a different type.

ErikR
  • 51,541
  • 9
  • 73
  • 124
  • Why does polymorphism affect its expression value? – Kevin Meredith Jun 22 '16 at 04:11
  • 3
    I think the key here is that a “value” with a typeclass constraint on it, such as `Num a => a`, is not really a plain value. Instead, it is a effectively a *function* from a typeclass dictionary to a value. – Alexis King Jun 22 '16 at 04:40
  • @KevinMeredith It's impossible to *run* the `+` function without knowing which function it is. For example, a complex number will have two fields, both of which need to be added; the compiled code for that version of `+` is totally different. When you evaluated `x` (by typing `x` at the prompt) GHCi had to pick a concrete type (by defaulting; it would raise an error if defaulting rules didn't apply) and call that type's version of `+`. But `x` itself is *all* (Num) types; it's always an unevaluated thunk because you can always make new Num instances and then use `x` as those types. – Ben Jun 22 '16 at 05:04
  • @KevinMeredith Alexis Kind is 100% correct. During Haskell compilation the typeclasses get removed. This is done by introducing explicit "dictionary arguments" that bring around the information regarding which instance should be used. So `x` becomes a function with type `NumDict a -> a` where the type `NumDict a` contains the implementations for the `Num` operations for the type `a`. When you try to evaluate `x` it's type gets defaulted to `Integer` and thus you are actually doing `x NumDictInteger` where `NumDictInteger` is defined by the instance declaration of `Integer` for `Num`. – Bakuriu Jun 22 '16 at 07:11