Haskell/Monad transformers

We have seen how monads can help handling  actions, , 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  exception handling. While a type like  would work just fine, it would force us to do pattern matching within   do-blocks to extract values, something that the   monad was meant to spare us from.

Enter monad transformers: special types that allow us to roll two monads into a single one that shares the behavior of both.

Passphrase validation
Consider a real-life problem for IT staff worldwide: getting users to create strong passphrases. One approach: force the user to enter a minimum length with various irritating requirements (such as at least one capital letter, one number, one non-alphanumeric character, etc.)

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

First and foremost,  is an   action, as it needs to get input from the user. We also use, as we intend to return   in case the password does not pass the. Note, however, that we aren't actually using  as a monad here: the   block is in the   monad, and we just happen to   a   value inside it.

Monad transformers not only make it easier to write  but also simplify all the code instances. Our passphrase acquisition program could continue like this: The code uses one line to generate the  variable followed by further validation of the passphrase.

With monad transformers, we will be able to extract the passphrase in one go — without any pattern matching (or equivalent bureaucracy like ). The gains for our simple example might seem small but will scale up for more complex situations.

A simple monad transformer:
To simplify  and the code that uses it, we will define a monad transformer that gives the   monad some characteristics of the   monad; we will call it. That follows a convention where monad transformers have a " " appended to the name of the monad whose characteristics they provide.

is a wrapper around, where   can be any monad (  in our example): This data type definition specifies a  type constructor, parameterized over , with a data constructor, also called  , and a convenient accessor function  , with which we can access the underlying representation.

The whole point of monad transformers is that they transform monads into monads; and so we need to make  an instance of the   class:

It would also have been possible (though arguably less readable) to write the return function as:.

Starting from the first line of the  block: It may look a bit complicated, but aside from the copious amounts of wrapping and unwrapping, the implementation of 's bind works the same way as the implementation of  's familiar bind operator:
 * First, the  accessor unwraps   into an   computation. That shows us that the whole   block is in.
 * Still in the first line,  extracts a   value from the unwrapped computation.
 * The  statement tests  :
 * With, we return   into  ;
 * With, we apply   to the   from the  . Since   has   as result type, we need an extra   to put the result back into the   monad.
 * Finally, the  block as a whole has   type; so it is wrapped with the   constructor.

Why use the  constructor before the   block while we have the accessor   within  ? Well, the  block must be in the   monad, not in   (which lacks a defined bind operator at this point).

As usual, we also have to provide instances for the superclasses of,   and  :

In addition, it is convenient to make  an instance of a few other classes:

implements the  function, so we can take functions from the   monad and bring them into the   monad in order to use them in   blocks. As for  and , since   is an instance of those classes it makes sense to make the   an instance too.

Passphrase validation, simplified
The above passphrase validation example can now be simplified using the  monad transformer as follows:

The code is now simpler, especially in the user function. Most importantly, we do not have to manually check whether the result is  or  : the bind operator takes care of that for us.

Note how we use  to bring the functions   and   into the   monad. Also, since  is an instance of , checking for passphrase validity can be taken care of by a   statement, which will return   (i.e.  ) in case of a bad passphrase.

Incidentally, with the help of  it also becomes very easy to ask the user ad infinitum for a valid passphrase:

Running your new version of askPassphrase on ghci is easy:

A plethora of transformers
The transformers package provides modules with transformers for many common monads (, for instance, can be found in ). 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 precursor monad to refer to the non-transformer monad (e.g. Maybe in MaybeT) on which a transformer is based and base monad to refer to the other monad (e.g. IO in MaybeT IO) on which the transformer is applied.

To pick an arbitrary example,  is a computation which involves reading values from some environment of type   (the semantics of , the precursor monad) and performing some   in order to give a value of type. Since the bind operator and  for the transformer mirror the semantics of the precursor monad, a   block of type   will, from the outside, look a lot like a   block of the   monad, except that   actions become trivial to embed by using.

Type juggling
We have seen that the type constructor for  is a wrapper for a   value in the base monad. So, the corresponding accessor  gives us a value of type   - i.e. a value of the precursor monad returned in the base monad. Similarly, for the  and   transformers, which are built around lists and   respectively: and

Not all transformers are related to their precursor monads in this way, however. Unlike the precursor monads in the two examples above, the,  ,  , and   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.

Notice that the precursor monad type constructor is absent in the combined types. Without interesting data constructors (of the sort that  and lists have), there is no reason to retain the precursor monad type after unwrapping the transformed monad. It is also worth noting that in the latter three cases we have function types being wrapped. , for instance, turns state-transforming functions of the form  into state-transforming functions of the form  ; only the result type of the wrapped function goes into the base monad. is analogous. is different because of the semantics of  (the continuation monad): the result types of both the wrapped function and its function argument must be the same, and so the transformer puts both into the base monad. In general, there is no magic formula to create a transformer version of a monad; the form of each transformer depends on what makes sense in the context of its non-transformer type.

Lifting
We will now have a more detailed look at the  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. As we have seen in Understanding monads, it is a monad-specific version of :

applies a function  to a value within a monad. We can also look at it as a function of just one argument:

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

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

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

is the single method of the  class, found in. All monad transformers are instances of, and so   is available for them all.

There is a variant of  specific to   operations, called , which is the single method of the   class in.

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

Implementing
Implementing  is usually pretty straightforward. Consider the  transformer:

We begin with a monadic value of the base monad. With  (  would have worked just as fine), we slip the precursor monad (through the   constructor) underneath, so that we go from   to. Finally, we wrap things up with the  constructor. Note that the  here works in the base monad, just like the do-block wrapped by   in the implementation of   we saw early on was in the base monad.

The State transformer
As an additional example, we will now have a detailed look at the implementation of. 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, the StateT transformer is built upon the definition:

will have the following  instance, here shown alongside the one for the precursor state monad:

Our definition of  makes use of the   function of the base monad. uses a do-block to perform a computation in the base monad.

If the combined monads  are to be used as state monads, we will certainly want the all-important   and   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  class, found in, has   and   as methods:

There are  instances for state monads wrapped by other transformers, such as. They bring us extra convenience by making it unnecessary to lift uses of  and   explicitly, as the   instance for the combined monads handles the lifting for us.

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

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

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

The  function creates a   state transformation function that binds the computation in the base monad to a function that packages the result with the input state. If, for instance, we apply StateT to the List monad, a function that returns a list (i.e., a computation in the List monad) can be lifted into  where it becomes a function that returns a. I.e. the lifted computation produces multiple (value,state) pairs from its input state. This "forks" the computation in StateT, creating a different branch of the computation for each value in the list returned by the lifted function. Of course, applying  to a different monad will produce different semantics for the   function.

Acknowledgements
This module uses a number of excerpts from All About Monads, with permission from its author Jeff Newbern.

Haskell/Monad transformers