In the MonadTrans class:
class MonadTrans t where
-- | Lift a computation from the argument monad to the constructed monad.
lift :: Monad m => m a -> t m a
why isn’t t m constrained to be a Monad? i.e., why not:
{-# LANGUAGE MultiParamTypeClasses #-}
class Monad (t m) => MonadTrans t m where
lift :: Monad m => m a -> t m a
If the answer is “because that’s just the way it is”, that’s fine — it’s just confusing for a n008.
You suggested the following:
…but does that really mean what you want? It seems you want to express something like “a type
tmay be an instance ofMonadTransif, for allm :: * -> *wheremis an instance ofMonad,t mis also an instance ofMonad“.What the class definition above actually says is more like “types
tandmmay constitute an instance ofMonadTransif, for those specific types,t mis an instance ofMonad“. Consider carefully the difference, and the implied potential for instances that may not be what you’d want.In the general case, every parameter of a type class is an independent “argument”, a fact which has been a bountiful source of both headaches and GHC extensions as people have attempted to use MPTCs.
Which isn’t to say that such a definition couldn’t be used anyway–as you point out, the current definition is not ideal either. The age-old problem “Why
Data.SetIs Not aFunctor” is related, and such issues helped motivate the recentConstraintKindstomfoolery.The ultimate answer to “why not” here is almost certainly the one given by Daniel Fischer in the comments–because
MonadTransis pretty core functionality, it would be undesirable to make it depend on some terrifying cascade of increasingly arcane GHC extensions.