3
votes

I read (for example here and here) that all of the base monads (Mabye, Error, ...) are derived from their corresponding monad transformers (MaybeT, ErrorT, ...) using the identity monad Identity. An example would be:

type Maybe a = MaybeT Identity a

But that of course doesn't result in a constructor for Maybe a. And in the sources MaybeT is defined as newtype MaybeT m a = MaybeT (m (Maybe a)).

Am I missing something important? How could one derive a base monad using the corresponding monad transformer and the identitiy monad resulting in a concrete
constructor that can be matched against?

2
Maybe is defined in base, monad transformers generally come from a library like transformers or mtl. The Error monad also comes from a library, along with State, Reader, and Writer. In this case, Maybe and MaybeT are the odd ones out.bheklilr
MaybeT Identity a is equivalent to Maybe a -- it reduces to a newtype MaybeT around Identity (Maybe a) -- but it's not literally the same thing, partially because Maybe is treated as a data structure first and a monad second.Louis Wasserman
"An example would be type Maybe a = MaybeT Identity a." No, but a correct example would be type State s = StateT s Identity.Daniel Wagner

2 Answers

3
votes

Different approaches are being used here.

Sometimes, the base monad Foo is defined in terms of its transformer as FooT Identity. For example, State from transformer package, as Daniel Wagner points out.

Other times, the base monad Foo is defined independently. In these cases, it usually happens that Foo and FooT Indentity are distinct types, which however are isomorphic. This means that you can convert between both types without losing any information.

I guess that since Maybe is defined in the Haskell report as a Prelude type, we can not easily redefine it as the isomorphic MaybeT Identity. Indeed, since it's common to destruct/eliminate values in Maybe a by pattern matching against Nothing and Just _, we can't use another definition. If we had user-definable patterns we could use pattern Just x = Module.Just (Identity x), but we have not these (for now).

Instead, other monads such as State are not in the Prelude, nor in the Haskell report. They are also not typically destructed via pattern matching by whomever is importing Control.Monad.State. In such cases, it felt less harmful to move to the StateT Identity variant.

2
votes

The Maybe monad is not defined as MaybeT Identity a for backwards compatibility, since Maybe was part of GHC long before MaybeT.

You are correct that using a monad transformer with Identity would not result in a type constructor that can be matched on. Fortunately, I've never had to pattern match on monad constructors when using the monad transformer paradigm. Instead, you can use do notation and monad operations (liftM, runReaderT, etc).