Haskell/Monad transformers

From Wikibooks, open books for an open world
Jump to: navigation, search

We have seen how monads can help handling IO actions, Maybe, lists, and state. With monads providing a common way to use such useful general-purpose tools, a natural thing we might want to do is using the capabilities of several monads at once. For instance, a function could use both I/O and Maybe exception handling. While a type like IO (Maybe a) would work just fine, it would force us to do pattern matching within IO do-blocks to extract values, something that the Maybe monad was meant to spare us from.


Passphrase validation[edit]


Here's a Haskell function to acquire a passphrase from a user:

getPassphrase :: IO (Maybe String)
getPassphrase = do s <- getLine
                   if isValid s then return $ Just s
                                else return Nothing

isValid :: String -> Bool
isValid s = length s >= 8
            && any isAlpha s
            && any isNumber s
            && any isPunctuation s



askPassphrase :: IO ()
askPassphrase = do putStrLn "Insert your new passphrase:"
                   maybe_value <- getPassphrase
                   if isJust maybe_value
                     then do putStrLn "Storing in database..." -- do stuff
                     else putStrLn "Passphrase invalid."



A simple monad transformer: MaybeT[edit]




This data type definition specifies a MaybeT type constructor, parameterized over m, with a term constructor, also called MaybeT, and a convenient accessor function runMaybeT, with which we can access the underlying representation.


instance Monad m => Monad (MaybeT m) where
    return  = MaybeT . return . Just




                      case maybe_value of
                           Nothing    -> return Nothing
                           Just value -> runMaybeT $ f value

Starting from the first line of the do block:

  • The case statement tests maybe_value:
    • With Nothing, we return Nothing into m;


-- (>>=) for the Maybe monad
maybe_value >>= f = case maybe_value of
                        Nothing -> Nothing
                        Just value -> f value





instance Monad m => MonadPlus (MaybeT m) where
    mzero     = MaybeT $ return Nothing
    mplus x y = MaybeT $ do maybe_value <- runMaybeT x
                            case maybe_value of
                                 Nothing    -> runMaybeT y
                                 Just _     -> return maybe_value

instance MonadTrans MaybeT where
    lift = MaybeT . (liftM Just)


Application to the passphrase example[edit]


getValidPassphrase :: MaybeT IO String
getValidPassphrase = do s <- lift getLine
                        guard (isValid s) -- MonadPlus provides guard.
                        return s

askPassphrase :: MaybeT IO ()
                   value <- getValidPassphrase
                   lift $ putStrLn "Storing in database..."




askPassword :: MaybeT IO ()
                 value <- msum $ repeat getValidPassphrase
                 lift $ putStrLn "Storing in database..."

A plethora of transformers[edit]

The transformers package provides modules with transformers for many common monads (MaybeT, for instance, can be found in Control.Monad.Trans.Maybe). These are defined consistently with their non-transformer versions; that is, the implementation is basically the same except with the extra wrapping and unwrapping needed to thread the other monad. From this point on, we will use base monad to refer to the non-transformer monad (e.g. Maybe in MaybeT) on which a transformer is based and inner monad to refer to the other monad (e.g. IO in MaybeT IO) on which the transformer is applied.


Type juggling[edit]

We have seen that the type constructor for MaybeT is a wrapper for a Maybe value in the inner monad. So, the corresponding accessor runMaybeT gives us a value of type m (Maybe a) - i.e. a value of the base monad returned in the inner monad. Similarly, for the ListT and ExceptT transformers, which are built around lists and Either respectively:

runListT :: ListT m a -> m [a]


runExceptT :: ExceptT e m a -> m (Either e a)

Not all transformers are related to their base monads in this way, however. Unlike the base monads in the two examples above, the Writer, Reader, State, and Cont monads have neither multiple constructors nor constructors with multiple arguments. For that reason, they have run... functions which act as simple unwrappers, analogous to the run...T of the transformer versions. The table below shows the result types of the run... and run...T functions in each case, which may be thought of as the types wrapped by the base and transformed monads respectively.[1]

Base Monad Transformer Original Type
("wrapped" by base)
Combined Type
("wrapped" by transformer)
Reader ReaderT r -> a r -> m a



We will now have a more detailed look at the lift function, which is critical in day-to-day use of monad transformers. The first thing to clarify is the name "lift". One function with a similar name that we already know is liftM. As we have seen in Understanding monads, it is a monad-specific version of fmap:


liftM applies a function (a -> b) to a value within a monad m. We can also look at it as a function of just one argument:


liftM converts a plain function into one that acts within m. By "lifting", we refer to bringing something into something else — in this case, a function into a monad.

liftM allows us to apply a plain function to a monadic value without needing do-blocks or other such tricks:

do notation liftM
do x <- monadicValue
   return (f x)
liftM f monadicValue

The lift function plays an analogous role when working with monad transformers. It brings (or, to use another common word for that, promotes) inner monad computations to the combined monad. By doing so, it allows us to easily insert inner monad computations as part of a larger computation in the combined monad.

lift is the single method of the MonadTrans class, found in Control.Monad.Trans.Class. All monad transformers are instances of MonadTrans, and so lift is available for them all.

class MonadTrans t where


class (Monad m) => MonadIO m where
   liftIO :: IO a -> m a

liftIO can be convenient when multiple transformers are stacked into a single combined monad. In such cases, IO is always the innermost monad, and so we typically need more than one lift to bring IO values to the top of the stack. liftIO is defined for the instances in a way that allows us to bring an IO value from any depth while writing the function a single time.

Implementing lift[edit]

Implementing lift is usually pretty straightforward. Consider the MaybeT transformer:

instance MonadTrans MaybeT where
    lift m = MaybeT (liftM Just m)

We begin with a monadic value of the inner monad. With liftM (fmap would have worked just as fine), we slip the base monad (through the Just constructor) underneath, so that we go from m a to m (Maybe a)). Finally, we use the MaybeT constructor to wrap up the monadic sandwich. Note that the liftM here works in the inner monad, just like the do-block wrapped by MaybeT in the implementation of (>>=) we saw early on was in the inner monad.

  2. Identity is a trivial functor, defined in Data.Functor.Identity as:
    newtype Identity a = Identity { runIdentity :: a }
    It has the following Monad instance:
    instance Monad Identity where
        return a = Identity a
        m >>= k  = k (runIdentity m)
    Implement a monad transformer IdentityT, analogous to Identity but wrapping values of type m a rather than a. Write at least its Monad and MonadTrans instances.

Implementing transformers[edit]

The State transformer[edit]

As an additional example, we will now have a detailed look at the implementation of StateT. You might want to review the section on the State monad before continuing.

Just as the State monad might have been built upon the definition newtype State s a = State { runState :: (s -> (a,s)) }, the StateT transformer is built upon the definition:


StateT s m will have the following Monad instance, here shown alongside the one for the base state monad:

State StateT
newtype State s a =

instance Monad (State s) where
    let (v,s') = x s
    in runState (f v) s'
newtype StateT s m a =


Our definition of return makes use of the return function of the inner monad. (>>=) uses a do-block to perform a computation in the inner monad.


Incidentally, we can now finally explain why, back in the chapter about State, there was a state function instead of a State constructor. In the transformers and mtl packages, State s is implemented as a type synonym for StateT s Identity, with Identity being the dummy monad introduced in an exercise of the previous section. The resulting monad is equivalent to the one defined using newtype that we have used up to now.

If the combined monads StateT s m are to be used as state monads, we will certainly want the all-important get and put operations. Here, we will show definitions in the style of the mtl package. In addition to the monad transformers themselves, mtl provides type classes for the essential operations of common monads. For instance, the MonadState class, found in Control.Monad.State, has get and put as methods:



instance (Monad m) => MonadState s (StateT s m) should be read as: "For any type s and any instance of Monad m, s and StateT s m together form an instance of MonadState". s and m correspond to the state and the inner monad, respectively. s is an independent part of the instance specification so that the methods can refer to it − for instance, the type of put is s -> StateT s m ().

There are MonadState instances for state monads wrapped by other transformers, such as MonadState s m => MonadState s (MaybeT m). They bring us extra convenience by making it unnecessary to lift uses of get and put explicitly, as the MonadState instance for the combined monads handles the lifting for us.

It can also be useful to lift instances that might be available for the inner monad to the combined monad. For instance, all combined monads in which StateT is used with an instance of MonadPlus can be made instances of MonadPlus:

  mzero = StateT $ \_ -> mzero

The implementations of mzero and mplus do the obvious thing; that is, delegating the actual work to the instance of the inner monad.

Lest we forget, the monad transformer must have a MonadTrans, so that we can use lift:

instance MonadTrans (StateT s) where


  1. Implement state :: MonadState s m => (s -> (a, s)) -> m a in terms of get and put.
  2. Are MaybeT (State s) and StateT s Maybe equivalent? (Hint: one approach is comparing what the run...T unwrappers produce in each case.)



