In another thread bottoms ⊥ and levity are discussed. The classic interpretation of bottom is “does not yield a value when evaluated”, e.g. in every lifted type there is
bottom :: a
bottom = bottom
where evaluating bottom causes an infinite loop. Now the GHC commentary on the type Type says that A type is lifted iff it has bottom as an element. In particular, Int# is unlifted and thus should not have a bottom element. Nevertheless, one can define the function
unpack :: Int -> Int#
unpack (I# x) = x
But where does unpack map bottom to? Certainly no number. The documentation says that there is no ⊥ in Int#. But apparently there is: One can evaluate unpack bottom and GHCi will throw a type error at run-time. So it seems there are three kinds of bottoms:
- bindable divergent bottoms of lifted types, as in
bottom = bottom - unbindable bottoms of unlifted types, as in
unpack bottom. Unbindable in the sense thatbot = unpack bottomdoes not compile, yet as an expression it clearly exists. - bindable errors as in
Prelude.undefinedthat when evaluated cause the RTS to abort immediately.
The wiki page for ⊥ glosses over the second kind.
My question is: Could there exist an implementation of Haskell where unpack does not compile? That is, is the existence of unpack a deficiency in GHCs implementation of unlifted types or a necessary wart in any implementation of lambda calculus with pattern matching?
I have the impression that if we define “A type X has x as an element” as “One can write a named top-level expression of type X that evaluates to x” then indeed Int# has no bottom, but if we accept the more permissive definition "A type X has x as an element if there exists a function f with f () = x" then we must conclude that Int# has a bottom.