12

Why is there no monad instance for Control.Applicative.Const? Is following definition correct, or violates it the monad laws?

instance Monoid a => Monad (Const a) where
  return _ = Const mempty
  (Const x) >>= _ = Const x

And can you think of any useful application?

Landei
  • 54,104
  • 13
  • 100
  • 195

2 Answers2

23

It violates the left identity law: return x >>= f must be the same as f x, but consider f x = Const (x + 1).

ehird
  • 40,602
  • 3
  • 180
  • 182
  • Actually you have to use a monoid like `Sum`, but the observation is correct. And from your example it's clear that there is no way to fix the monad instance. – Landei Jul 17 '12 at 20:57
  • 9
    Reassuringly, the special case `Const ()` is a monad. Indeed, it's the terminal monad. – pigworker Jul 18 '12 at 00:08
1

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.