ehird's answer explains what's wrong with the instance in the question. Here's a more in-depth explanation as to why there can be no other instance that works either, even if you were to choose constraints other than Monoid
, unless the type has exactly one inhabitant (e.g., ()
). Any given type either has zero inhabitants, one inhabitant, or at least two inhabitants.
Case 1: zero inhabitants
You could write this total function, an obvious contradiction:
{-# LANGUAGE EmptyCase #-}
oops :: void
oops = case getConst (return () :: Const TheEmptyType ()) of {}
Case 2: one inhabitant
This special case actually is possible: it's isomorphic to Proxy
. For completeness, here it is:
instance Monad (Const ()) where
return _ = Const ()
Const () >>= _ = Const ()
Case 3: at least two inhabitants
Let x
and y
be two different inhabitants of your chosen type. Write this helper function:
f False = Const x
f True = Const y
Now consider these two instantiations of the left identity law:
return False >>= f = f False
return True >>= f = f True
By parametricity, there's no way to implement return
such that return False
and return True
are different, so you end up with the same value having to equal both Const x
and Const y
, which is a contradiction since we said earlier that x
and y
were different.