# mtl is Not a Monad Transformer Library

by Justin Le ♦

Source ♦ Markdown ♦ LaTeX ♦ Posted in Haskell, Ramblings ♦ Comments

*mtl* is not a monad transformer library — contrary to popular conception. I believe that this commonly spread myth is due in part to some rather peculiar branding choices (the name of the library) and in part to some historical accidents (*mtl* was, in the distant and pre-historic past, indeed a monad transformer library).

What is *mtl*? It is a library of *interfaces* you can provide to your own types, in the form of typeclasses. It abstracts over *different design patterns* for different types, in the form of typeclasses. Just like Functor abstracts over “things that can be fmapped”. *mtl* provides typeclasses abstracting over many useful patterns that many types satisfy — patterns involving different sorts of “effects”.

## The Patterns

### MonadError

`MonadError`

is a generic interface over things where you can throw “errors” of a specific type `e`

, and “catch” them. It offers two methods: `throwError :: e -> m a`

, and `catchError :: m a -> (e -> m a) -> m a`

, which does what you’d expect from an error monad.

Now, we have a generic interface to work on *all specfic type error-throwing Monads*. The `Either`

type comes to mind as an obvious candidate:

```
instance MonadError e (Either e) where
throwError = Left
catchError s f = case s of
Right _ -> s
Left e -> f e
```

But there are definitely other instances possible. How about for `IO`

and `IOException`

s, in specific?

```
instance MonadError IOException IO where
throwError = ioError
catchErrror = catch -- will not catch non-IOExceptions
```

This is great, because we can now write code *generic* over *all* specific-type error things!

#### Error behavior…for free!

If we’re clever enough, we can actually imbue any arbitrary Monad `m`

with rudimentary, basic, “dumb” error handling by using the `ExceptT`

type. An `ExceptT e m`

behaves *just* like our original Monad `m`

in every way…except now, we have access to rudmentary implementations of side-channels of `throwError`

and `catchError`

.

This is pretty useful…to be able to add short-circuiting error behavior to any Monad we wanted. But remember, `ExceptT`

is not the “point” of `MonadError`

. It’s just one way to generate instances for free given a Monad. The real power of `MonadError`

is in the ability to write generically over many Monads with some sort of “error” behavior, like `Either`

or `IO`

.

### MonadState

A `MonadState s m`

is a Monad `m`

where, during in the context of `m`

, you have access to a global state of type `s`

that you can modify.

You can “get” it with `get :: m s`

. You can modify it with `modify :: (s -> s) -> m ()`

. You can replace it with `put :: s -> m ()`

.

There are a lot of types that can offer this type of interface. You might have, for example, a type where “getting” the state comes from reading an `IORef`

, and “putting” it comes from writing to the `IORef`

. Or maybe the state can come from a a query to a database…where `get`

queries a database in IO, and `put`

writes to the database.

`MonadState`

, as a typeclass, gives you the ability to *write generically over all Monads with state*. You can now write generically over those database state things…or those IORef state things…or those web query things…or anything that cares to implement the interface!

`MonadState`

says, “the functions and actions I write can work for *all* Monads offering state I can modify!” An action of type `MonadState String m => m Double`

can create a `Double`

from *any* monad offering some sort of `String`

state.

#### State…for free!

Again, we can actually imbue any Monad `m`

with some very rudimentary, “dumb” stateful interface, using a type called `StateT`

. A `StateT s m`

behaves just like our monad `m`

(be it `IO`

, `Reader`

, `ST`

, `STM`

…), except now we have access to a rudimentary state getting-and-putting mechanism on a state of type `s`

, using a form of function composition. The implementation of the `StateT`

handles it under the hood.

Obviously, being able to add a rudimentary stateful interface on top of any Monad is pretty useful. Very useful, in fact!

But remember, this isn’t the *point* of `MonadState`

. `MonadState`

doesn’t exist for `StateT`

. `StateT`

is just a way to generate a free instance of `MonadState`

if you just want to add rudimentary statefulness to an existing Monad. But there are many instances of `MonadState`

…really, `MonadState`

has nothing to do with `StateT`

fundamentally, any more than `Monad`

has to do with `Maybe`

fundamentally. And `MonadState`

and `StateT`

don’t even come from the same library!

*mtl* offers a generic interface for working with all monads offering a statey API.

### MonadReader

`MonadReader`

is more or less the same thing…it offers a generic interface to work on monads that have access to some sort of global, unchanging “environment”. An example might be a Monad where you could work with command line arguments, or environment variables, assuming they are read once and fixed when things start up. You could access the command line arguments with `ask`

, and use them in your program.

### MonadIO

This one is actaully from *transformers*, but it gives a nice picture. Any `MonadIO m`

is a `Monad`

that allows you to embed and sequence in any arbitrary IO action. This is pretty useful! In the *persistent* database library, for example — the main “database access type monad” can sequence actions that access databases *and* arbitrary IO actions, as well. A lot of resource managers and DSL’s offer the ability to sequence IO in the middle of all the other actions.

That’s what `MonadIO`

is for — it allows you to write functions and say, “hey, my function is generic over *all* things that can embed IO…anything that can embed IO can sequence my function/type”. The generic “embedding” action is `liftIO :: MonadIO m => IO a -> m a`

.

**Aside**

You know…ideally, all of these typeclasses would have laws, so we could make conclusions and apply equational reasoning to generically written functions.

Some of the laws are simple…`liftIO`

from `MonadIO`

should be a monad morphism. But the rest of them don’t really have any well-established laws. This is a bit of a shame, because we’d really like to be able to apply reasoning to generic functions.

People have suggested `MonadState`

have laws similar to how view/set/over interact in the *lens* laws. But as of now, most of we have in terms of our capability of analyzing generic programs is rough heuristins/feelings about what “should” be right.

A bit un-ideal, but…in practice, this ends up working not-so-badly :)

## Not a Monad Transformer Library

So, let’s work together to dispel the myth that *mtl* is a monad transformer library. It really has nothing to do with monad transformers at all…any more than `Control.Monad`

is an “IO module”, or `Control.Monoid`

is a “list module”. Transformers don’t even come from the *mtl* library!

Together, we can overcome this myth. We can show people that we can live in a world where we can combine effects, work generically in Monads with *multiple types of effects* by writing functions generic over many different *mtl* typeclasses at once! (`MonadState`

+ `MonadIO`

, maybe?)

We don’t *have to* reach for Monad transformers to work with combined effects. We can write our own combined effects monads and just write the instances…or we can write generically and not even care about what Monad we actually use in the end. We don’t have to teach people to be afraid of monad transformers as if they were the only way to get things done, and *mtl* is tied to them like a ball and chain.

*mtl* is not a Monad transformer library. How liberating!