https://wiki.haskell.org/Hask:
Consider:
undef1 = undefined :: a -> b undef2 = \_ -> undefined
Note that these are not the same value:
seq undef1 () = undefined seq undef2 () = ()
This might be a problem, because
undef1 . id = undef2
. In order to make Hask a category, we define two functionsf
andg
as the same morphism iff x = g x
for allx
. Thusundef1
andundef2
are different values, but the same morphism in Hask.
What does it mean or how can I check, that:
undef1
and undef2
are different values, but the same morphism?
In Haskell, we have this idea that every expression can be evaluated to a particular "value", and we might be interested in determining if two expressions have the "same" value.
Informally, we know that some values (e.g., value
2
and3
of typeInteger
) can be compared directly. Other values, likesqrt
andid
of typeDouble -> Double
can be compared, as @pigworker notes, by constructing an expression that "witnesses" a difference in directly comparable values:Here, we can conclude that
sqrt
andid
are different values. If there is no such witness, then the values are the same.If we look at the monomorphic specializations of
undef1
andundef2
to the type() -> ()
given by:how can we tell if these are different values?
Well, we need to find an expression that witnesses a difference, and one is given above. The two expressions:
have different values, according to GHCi. We could also show this directly, using our understanding of Haskell semantics:
So, what's the problem? Well, when considering Hask as a category where the objects are types and the morphisms are (monomorphic) functions, we implicitly need a concept of identity/equality for objects and morphisms.
Object identity/equality is easy: two objects (monomorphic Haskell types) are equal if and only if they are the same type. Morphism identity/equality is harder. Because morphisms in Hask are Haskell values (of monomorphic function types), it would be tempting to define equality of morphisms to be the same as equality of values, as above.
If we used this definition, then
undef1
andundef2
would be different morphisms, because we have proved they are different Haskell values above.However, if we compared
undef1 . id
andundef2
, we would discover that they have the same value. That is, there is no expression that witnesses a difference between them. Proving this is a little tough, but see below.Anyway, we now have a contradiction in our Hask category theory. Because
id
is the (polymorphic family of) identity morphisms in Hask, we must have:so we simultaneously have
undef1 /= undef2
because of the witness above, butundef1 = undef2
by the previous argument.The only way to avoid this contradiction is to give up the idea of defining equality of morphisms in Hask as equality of the underlying Haskell values.
One alternative definition of equality of morphisms in Hask that has been offered is the weaker definition that two morphisms
f
andg
are equal if and only if they satisfyf x = g x
for all valuesx
(including_|_
). Note that there's still an ambiguity here. Iff x
andg x
are themselves Haskell functions and so morphisms, doesf x = g x
mean equality of the morphismsf x
andg x
or equality of the Haskell valuesf x
andg x
? Let's ignore this problem for now.Under this alternative definition,
undef1
andundef2
are equal as morphisms, because we can showundef1 x = undef2 x
for all possible valuesx
of type()
(namely()
and_|_
). That is, applied to()
, they give:and applied to
_|_
they give:Similarly,
undef1 . id
andundef2
can be shown to be equal as morphisms in Hask by this definition (in fact, they were equal as Haskell values which implies they're equal according to the weaker definition of equality of Hask morphisms), so there's no contradiction.However, if you follow the link provided by @n.m., you can see that there's more work to do in terms of formalizing the meaning of equality of Haskell values and precisely giving an appropriate definition of equality of Hask morphisms before we'd really feel comfortable believing that there is a contradiction-free Hask category.
Proof that
undef1 . id = undef2
as Haskell ValuesFor the reasons above, this proof is necessarily a little informal, but here's the idea.
If we are trying to witness a difference between functions
f
andg
, the only way a witnessing expression can use these values is by applying them to a valuex
or by evaluating them to WHNF usingseq
. Iff
andg
are known to be equal as Hask morphisms, then we already havef x = g x
for allx
, so no expression can witness a difference based on application. The only remaining thing to check is that when they are evaluated to WHNF they are either both defined (in which case, by the previous assumption, they will yield the same values when applied) or they are both undefined.So, for
undef1 . id
andundef2
, we just need to ensure that they are either both defined or both undefined when evaluated to WHNF. It's easy to see that they both, in fact, have defined WHNFs:We already established above that
undef1 x = undef2 x
for allx
. Technically, we ought to show that:with equality as Haskell values for all
x
, which establishes that(undef1 . id) x = undef2 x
for allx
. Together with the fact that both have defined WHNFs above, this is enough to show thatundef1 . id = undef2
with equality as Haskell values.