I would like to define a monad instance with the container M as monad and with the contained type a which should be a member of class Show. This constraint (that a is member of Show) should be ensured by the type system.
I gave it a try like this, but M is unfortunately not of the right Kind:
data M = forall a. Show a => M a
instance Monad M where
return x = M x
All other attempts to achieve that, run into the following problem: Since Monad is a constructor class, I don’t have explicit access to the type a of the contained element(s), so I can’t restrict it.
Does anyone know a solution to this without defining a new Monad class?
Well, it is actually possible to restrict the parameters of a type constructor in some sense, using GADTs:
Unfortunately this doesn’t actually help you here. In a way it actually makes things worse, because rather than having a
Monadinstance without the constraint, it becomes impossible to write the instance at all.If you look at the above constructor type signature, it clearly resembles
return–which demonstrates why what you’re doing is fundamentally impossible. The type for return is:(Monad m) => a -> m a, and as always unbound type variables are implicitly universally quantified at the outermost level, so you can read that as “for all possible typesa, and all possible typesmwhich are instances ofMonad, given a value of typeayou can construct a value of typem a“. The “for all” phrasing is quite literal there–the type of return isn’t just using a type variable, it’s actively asserting that any typeawhatsoever must be allowed.So, in short, no. There’s no way to do what you want because the standard
Monadclass explicitly specifies the opposite.