A few weeks ago, we addressed some important steps to advance past the “beginner” stage of Haskell. We learned how to organize your project and how to find the relevant documentation. This week we’re going to continue to look at another place where we can make a big step up. We’ll explore how to expand our vocabulary on monad usage.

Monads are a vital component of Haskell. You can’t use a lot of libraries unless you know how to incorporate their monadic functions. These functions often involve a monad that is custom to that library. When you’re first starting out, it can be hard to know how to incorporate these monads into the rest of your program.

In this article, we’ll focus on a specific pattern a lot of monads and libraries use. I call this pattern the “run” pattern. Often, you’ll use a function with a name like `runXXX`

or `runXXXT`

, where `XXX`

is the name of the monad. These functions will always take a monadic expression as their first argument. Then they'll also take some other initialization information, and finally return some output. This output can either be in pure form or a different monad you’re already using like `IO`

. We’ll start by seeing how this works with the `State`

monad, and then move onto some other libraries.

Once you grasp this topic, it seems very simple. But a lot of us first learned monads with a bad mental model. For instance, the first thing I learned about monads was that they had side effects. And thus, you can only call them from places that have the same side effects. This applies to IO but doesn’t generalize to other monads. So even though it seems obvious now, I struggled to learn this idea at first. But let’s start looking at some examples of this pattern.

For a more in depth look at monads, check out our series on Functional Data Structures! We start by learning about simpler things like functors. Then we eventually work our way up to monads and even monad transformers!

### The Basics of “Run”: The State Monad

Let’s start by recalling the `State`

monad. This monad has a single type parameter, and we can access this type as a global read/write state. Here’s an example function written in the `State`

monad:

`stateExample :: State Int (Int, Int, Int)`

stateExample = do

a <- get

modify (+1)

b <- get

put 5

c <- get

return (a, b, c)

If this function is confusing, you should take a look at the documentation for `State`

. It’ll at least show you the relevant type signatures. First we read the initial state. Then we modify it with some function. Finally we completely change it.

In the example above, if our initial state is 1, we’ll return `(1,2,5)`

as the result. If the initial state is 2, we’ll return `(2,3,5)`

. But suppose we have a pure function. How do we call our state function?

`pureFunction :: Int -> Int`

pureFunction = ???

The answer is the `runState`

function. We can check the documentation and find its type:

`runState :: State s a -> s -> (a, s)`

This function has two parameters. The first is a `State`

action. We’ll pass our function above as this parameter! Then the second is the initial state, and this is how we’ll configure it. Then the result is pure. It contains our result, as well as the final value of the state. So here’s a sample call we can make that gives us this monadic expression in our pure function. We’ll call it from a `where`

clause, and discard the final state:

`pureFunction :: Int -> Int`

pureFunction input = a + b + c

where

((a,b,c), _) = runState stateExample input

This is the simplest example of how we can use the `runXXX`

pattern.

### Upgrading to Transformers

Now, suppose our `State`

function isn’t quite pure. It now wants to print some of its output, so it’ll need the `IO`

monad. This means it’ll use the `StateT`

monad transformer over `IO`

:

`stateTExample :: StateT Int IO (Int, Int, Int)`

stateTExample = do

a <- get

lift $ print “Initial Value:”

lift $ print a

modify (+1)

b <- get

lift $ putStrLn “After adding 1:”

lift $ print b

put 5

c <- get

lift $ putStrLn “After setting as 5:”

lift $ print c

return (a, b, c)

Now instead of calling this function from a pure format, we’ll need to call it from an `IO`

function. But once again, we’ll use a `runXXX`

function. Now though, since we’re using a monad transformer, we won’t get a pure result. Instead, we’ll get our result in the underlying monad. This means we can call this function from `IO`

. So let’s examine the type of the `runStateT`

function. We’ve substituted `IO`

for the generic monad parameter `m`

:

`runStateT :: StateT s IO a -> s -> IO (a, s)`

It looks a lot like `runState`

, except for the extra `IO`

parameters! Instead of returning a pure tuple for the result, it returns an `IO`

action containing that result. Thus we can call it from the `IO`

monad.

`main :: IO ()`

main = do

putStrLn “Please enter a number.”

input <- read <$> getLine

results <- runStateT stateTExample input

print results

We’ll get the following output as a result:

`Please enter a number.`

10

Initial Value:

10

After adding 1

11

After setting as 5

5

(10, 11, 5)

### Using “run” for Libraries

This pattern will often extend into libraries you use. For example, in our series on parsing, we examine the Megaparsec library. A lot of the individual parser combinators in that library exist in the `Parsec`

or `ParsecT`

monad. So we can combine a bunch of different parsers together into one function.

But then to run that function from your normal `IO`

code (or another monad), you need to use the `runParserT`

function. Let’s look at its type signature:

`runParserT`

:: Monad m

-> ParsecT e s m a

-> String -- Name of source file

-> s -- Input for parser

-> m (Either (ParseError (Token s) e) a)

There are a lot of type parameters there that you don’t need to understand. But the structure is the same. The first parameter to our `run`

function is the monadic action. Then we’ll supply some other inputs we need. Then we get some result, wrapped in an outer monad (such as `IO`

).

We can see the same pattern if we use the `servant-client`

library to make client-side API calls. Any call you make to your API will be in the `ClientM`

monad. Now here’s the type signature of the `runClientM`

function:

`runClientM :: ClientM a -> ClientEnv -> IO (Either ServantError a)`

So again, the same pattern emerges. We’ll compose our monadic action and pass that as the first parameter. Then we’ll provide some initial state, in this case a `ClientEnv`

. Finally, we’ll get our result (`Either ServantError a`

) wrapped in an outer monad (`IO`

).

### Monads within Expressions

It’s also important to remember that a lot of basic monads work without even needing a `runXXX`

function! For instance, you can use a `Maybe`

or `Either`

monad to take out some of your error handling logic:

`divideIfEven :: Int -> Maybe Int`

divideIfEven x = if x `mod` 2 == 0

then Just (x `quot` 2)

else Nothing

`dividesBy8 :: Int -> Bool`

dividesBy8 = case thirdResult of

Just _ -> True

Nothing -> False

where

thirdResult :: Maybe Int

thirdResult = do

y <- divideIfEven x

z <- divideIfEven y

divideIfEven z

### Conclusion

Monads are the key to using a lot of different Haskell libraries. But when you’re first starting out, it can be very confusing how you call into these functions from your code. The same applies with some common monad transformers like `Reader`

and `State`

. The most common pattern to look out for is the `runXXXT`

pattern. Master this pattern and you’re well on your to understanding monads and writing better Haskell!

For a closer look at monads and similar structures, make sure to read our series on Functional Data Structures. If the code in this article was confusing, you should definitely check it out! And if you’ve never written Haskell but want to start, download our Beginners Checklist!