haskellweak-head-normal-form

Confused by converting WHNF to NF in Haskell


In a simple example, converting WHNF to NF by printing works fine

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

But in a case, the type is not declared it doesn't work.

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

Can you explain in some details why conversion doesn't work in the last case?


Solution

  • Since in GHCi the monomoprhism restriction is disabled, the last x is a polymorphic value of type x :: Num a => a. So it is not a simple integer, but a kind-of function DictNum a -> a which is ready to create a value in any numeric type.

    Indeed, x :: Int, x :: Float, x :: Double will run and produce different values. These values are numerically the same, but computationally different, since they are representations in different types.

    Since x is, essentially, "multiple values, generated on demand", there is no single WHNF or NF here.

    Note that if we compute (x :: Int) + (x :: Int), then x is being recomputed twice: GHC in general will not "cache" the WHNF at type Int for successive computations. This is similar to f 3 + f 3, where f 3 is not cached (memoized).

    This duplicate computation is precisely what the monomorphism restriction tries to avoid.