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:
class Monad (t m) => MonadTrans t m where
lift :: Monad m => m a -> t m a
...but does that really mean what you want? It seems you want to express something like "a type t
may be an instance of MonadTrans
if, for all m :: * -> *
where m
is an instance of Monad
, t m
is also an instance of Monad
".
What the class definition above actually says is more like "types t
and m
may constitute an instance of MonadTrans
if, for those specific types, t m
is an instance of Monad
". 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.Set
Is Not a Functor
" is related, and such issues helped motivate the recent ConstraintKinds
tomfoolery.
The ultimate answer to "why not" here is almost certainly the one given by Daniel Fischer in the comments--because MonadTrans
is pretty core functionality, it would be undesirable to make it depend on some terrifying cascade of increasingly arcane GHC extensions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With