Monad Transformer Stacks

You will want to bookmark this page.

Generalizing the idea we discovered in the previous file into a pattern, we get something like this:

program :: forall m
         . MonadState StateType m
        => MonadWriter NonOutputData m
     -- => other needed type classes here in any order...
        => m ProgramFinalOutputType
program = do
  -- use all the functions from the type classes

--  StateT state         monad output
-- "IndexN possibleInput monad typeClassOutput"
runProgram :: Index3 input3 (       -- top of the stack
                Index2 input2 (
                  Index1 input1 (
                    Index0 input0   -- =
                      Identity      -- | bottom of the stack (the base monad)
                    output0         -- =
                  ) output1
                ) output2
              ) output3
        -- -> input0      -- =
        -- -> input1      -- | all needed initial args to
        -- -> input2      -- | `run[Word]T`/`runWord` go here
        -- -> input3      -- =
           -> Tuple (
                Tuple (
                  Tuple (
                    Tuple (
                      computationOutput
                      output3
                    )
                    output2
                  )
                  output1
                )
                output0
              )
runProgram program {- args -} =
  runIndex0 (                               -- bottom of the stack
    runIndex1T (
      runIndex2T (
        runIndex3T program index3Args   -- top of the stack
      ) index2Args
    ) index1Args
  ) index0Args

Note: when using ExceptT, MaybeT, or ListT, the outputs won't necessarily be Tuples.