As we have already mentioned, when we stack a monad transformer on a normal monad, the result is another monad. This suggests the possibility that we can again stack a monad transformer on top of our combined monad, in order to get a new monad and in fact, this is a common thing to do. Under what circumstances might we want to create such a stack?

If we need to talk to the outside world, we’ll have IO at the base of the stack. Otherwise, we will have some normal monad.

If we add a ReaderT layer, we give ourselves access to read-only configuration information.

Add a StateT layer, and we gain a global state that we can modify.

Should we need the ability to log events, we can add a WriterT layer.

The power of this approach is that we can customize the stack to our exact needs, specifying which kinds of effects we want to support.

As a small example of stacked monad
transformers in action, here is a reworking of the `countEntries`

function we developed earlier. We will modify it to recurse no
deeper into a directory tree than a given amount and to record the
maximum depth it reaches:

-- file: ch18/UglyStack.hs import System.Directory import System.FilePath import Control.Monad.Reader import Control.Monad.State data AppConfig = AppConfig { cfgMaxDepth :: Int } deriving (Show) data AppState = AppState { stDeepestReached :: Int } deriving (Show)

We use ReaderT to store configuration data, in the form of the maximum depth of recursion we will perform. We also ...

Start Free Trial

No credit card required