### Building Applications with Many Effects

So far in this book you’ve learned about different individual Monads, like IO actions, lists of values, and optional values. As you start to write more sophisticated applications, it’s frequently desirable to compose the properties of these individual Monads to build up types with new behaviors that combine the properties of individual monadic actions. This technique is used in a huge number of real world Haskell applications, and it will enable you to read and write real world professional Haskell applications.

In this chapter you’ll learn about how to compose monadic computations using Monad transformers. You’ll learn about some common Monad transformers provided by the MTL and Transformers libraries, and learn how to make use of tagless final encodings to use Monad transformers effectively.

You’ll be able to build new Monads that combine different sorts of monadic computations, like having a read-only environment, dealing with exception handling, and performing IO.

In the next chapter you will learn how to use Monad transformers to create a core application Monad out of an MTL stack, using the Monad transformers that you learn about in this chapter.

## Building Out The Monad Transformer Library

In this chapter we focused on two specific Monad transformers: `StateT`

and
`ExceptT`

. The `transformers`

library provides several other commonly used Monad
transformers. One of the most common Monad transformers is the `ReaderT`

transformer. This Monad transformer lets you write computations that have a
read-only environment:

`newtype ReaderT r m a = ReaderT {runReaderT :: r -> m a}`

The two basic operations for a `ReaderT`

Monad are `ask`

, which fetches the
value from the read-only environment, and`local`

, which lets you run a `ReaderT`

action with a modified local read-only environment. Their types are:

```
ask :: Monad m => ReaderT r m r
local :: Monad m => (r -> r) -> ReaderT r m a -> ReaderT r m a
```

In this exercise, write `Functor`

, `Applicative`

, `Monad`

, `MonadIO`

, and
`MonadTrans`

instances for `ReaderT`

, and provide a definition for both `ask`

and `local`

. Once you have created a working definition of `ReaderT`

, add a new
class called `MonadReader`

:

```
class Monad m => MonadReader r m | m -> r where
ask :: m r
local :: (r -> r) -> m a -> m a
```

Next, finish writing the following instances:

```
instance Monad m => MonadReader r (Reader.ReaderT r m) where
instance MonadReader r m => MonadReader r (ExceptT e m) where
instance MonadReader r m => MonadReader r (StateT s m) where
```

### Hint 1

Some high level hint text

### Hint 2

Some more detailed hint text

### Hint 3

Even more detailed hint text

### Solution

A complete solution for the exercise

## A New FilePackParser

Refactor the `FilePackParser`

application that you wrote earlier in this book to
use the following Monad:

```
newtype FilePackParser a = FilePackParser
runFilePackParser :: StateT Text (ExceptT Text IO) a } {
```

### Hint 1

Some high level hint text

### Hint 2

Some more detailed hint text

### Hint 3

Even more detailed hint text

### Solution

A complete solution for the exercise