[Haskell-cafe] trying to understand monad transformers....

wren ng thornton wren at freegeek.org
Wed Sep 10 00:54:33 EDT 2008

Daryoush Mehrtash wrote:
> The MaybeT transformer is defined as:
> newtype MaybeT m a = MaybeT {runMaybeT :: m (Maybe a)}
> ....
> Question:  What does "runMaybeT x" mean?

As for "what does it do", I think everyone else has handled that pretty 
well. As far as "what does it mean", it may help to think categorically.

For every monad |m| we have another monad |MaybeT m|. If we ignore some 
details, we can think of the transformed monad as |Maybe| composed with 
|m|, sic: |Maybe . m|. With this perspective, runMaybeT is inverting 
|MaybeT m| into |m . Maybe| by pushing the Maybe down over/through the 
monad m. Hence we can envision the function as:

  | runMaybeT           :: (MaybeT m) a -> (m . Maybe) a
  | runMaybeT NothingT   = return Nothing
  | runMaybeT (JustT ma) = fmap Just ma

The reason this is useful at all is that Maybe is not just any monad, 
but is also a primitive value in the system. That is, once we have a 
Maybe value we can treat it as a normal pure value that we can pattern 
match on etc. For other monads like Set, [ ], and LogicMonad this means 
that we can iterate over their elements rather than just treating them 
as functors. Whereas a |MaybeT m| value can't be accessed directly.

This explanation is leaving out details about transformers in general. 
The Maybe/MaybeT type is defined by Maybe(a)=a+1, which is to say it's 
the same as the type |a| plus one additional value. Given this 
definition it's easy to define runMaybeT like above. For other monads 
and monad transformers this conversion might not be so trivial because 
we'll need to thread state through the computation.

This is also the reason why the ordering of your transformer stack is 
important. When converting from the transformer to the composition, how 
to thread the state is non-trivial. This is just the same as saying that 
we can't reorder function compositions and still have the same results. 
A large class of functions do have reorderable compositions[1] just like 
a large class of monads have trivial state, but in general that's not 
the case for either of them.


Live well,

More information about the Haskell-Cafe mailing list