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 bottom
does not compile, yet as an expression it clearly exists. - bindable errors as in
Prelude.undefined
that 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.