Search code examples
haskellmonadsmonad-transformers

MaybeT's m in Type Signature


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.


Solution

  • To quote Learn You A Haskell:

    Another example of a parameterized type that we've already met is Map k v from Data.Map. The k is the type of the keys in a map and the v 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 the Ord 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 for Map 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 is toList, that just takes a mapping and converts it to an associative list. It's type signature is toList :: Map k a -> [(k, a)]. If Map k v had a type constraint in its data declaration, the type for toList would have to be toList :: 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.