Looking at MaybeT
:
λ: import Monad.Trans
λ: import Monad.Trans.Maybe
λ: :t MaybeT
MaybeT :: m (Maybe a) -> MaybeT m a
In MaybeT
's signature, can m
be any higher-kinded type, i.e. * -> *
?
I'm trying to learn Monad Transformers, so I was curious why the m
did not have a constraint of Monad
.
To quote Learn You A Haskell:
Another example of a parameterized type that we've already met is
Map k v
fromData.Map
. Thek
is the type of the keys in a map and thev
is the type of the values. This is a good example of where type parameters are very useful. Having maps parameterized enables us to have mappings from any type to any other type, as long as the type of the key is part of theOrd
type class. If we were defining a mapping type, we could add a type class constraint in the data declaration:data (Ord k) => Map k v = ...
However, it is a very strong convention in Haskell to never add type class constraints in data declarations. Why? Well, because we don't benefit a lot, but we end up writing more class constraints, even when we don't need them. If we put or don't put the
Ord k
constraint in the data declaration forMap k v
, we're going to have to put the constraint into functions that assume the keys in a map can be ordered. But if we don't put the constraint in the data declaration, we don't have to put(Ord k) =>
in the type declarations of functions that don't care whether the keys can be ordered or not. An example of such a function istoList
, that just takes a mapping and converts it to an associative list. It's type signature istoList :: Map k a -> [(k, a)]
. IfMap k v
had a type constraint in its data declaration, the type fortoList
would have to betoList :: Ord k => Map k a -> [(k, a)]
, even though the function doesn't do any comparing of keys by order.So don't put type constraints into data declarations even if it seems to make sense, because you'll have to put them into the function type declarations either way.
I hope that answers your question. Although the m
in MaybeT m a
is unconstrained yet there is an implicit assumption that m
is an instance of Monad
. In fact, if m
is not an instance of Monad
then you wouldn't be able to do much with a MaybeT m a
value because most functions would require that m
be an instance of Monad
.