I just got finished reading the paper Levity Polymorphism.
I had a question about why undefined can be levity-polymorphic when used as an unboxed type.
First, let's start with some definitions of boxity from the paper:
boxed:
A boxed value is represented by a pointer into the heap.
IntandBoolare examples of types that have boxed values.
unboxed:
The paper follows with some definitions of levity:
lifted:
A lifted type is one that is lazy.
A lifted type has on extra element beyond the normal ones, representing a non-terminating computation.
For example, the type
Boolis lifted, meaning that there are three different values forBool:True,False, and⊥(bottom).All lifted types MUST be boxed.
unlifted
An unlifted type is one that is strict.
The element
⊥does not exist in an unlifted type.Int#andChar#are examples of unlifted types.
The paper goes on to explain how GHC 8 provides functionality allowing type variables to have polymorphic levity.
This allows you to write a levity-polymorphic undefined with the following type:
undefined :: forall (r :: RuntimeRep). forall (a :: TYPE r). a
This says that undefined should work for any RuntimeRep, even unlifted types.
Here is an example of using undefined as an unboxed, unlifted Int# in GHCi:
> :set -XMagicHash
> import GHC.Prim
> import GHC.Exts
> I# (undefined :: Int#)
*** Exception: Prelude.undefined
I've always thought of undefined as being the same as ⊥ (bottom). However, the paper says, "The element ⊥ does not exist in an unlifted type."
What is going on here? Is undefined not actually ⊥ when used as an unlifted type? Am I misunderstanding something about the paper (or boxity or levity)?