🎓 A1Learner
🔍
0 of 50 lessons completed

Haskell Monad Transformers

A monad transformer adds one effect to another monad. It layers the new effect on top of the monad underneath.

ReaderT adds a read-only value

ReaderT carries one shared value for the whole block. The block asks for 21 and doubles it.

import Control.Monad.Trans.Reader
import Data.Functor.Identity
main :: IO ()
main = print (runIdentity (runReaderT (do n <- ask; return (n * 2)) 21))

StateT adds a changeable value

StateT carries a value that steps can replace. The block returns 41 and leaves 42 behind.

import Control.Monad.Trans.State
import Data.Functor.Identity
main :: IO ()
main = print (runIdentity (runStateT (do n <- get; put (n + 1); return n) 41))

The shared value can be text

The shared value is not always a number. The block asks for a colour and returns it unchanged.

import Control.Monad.Trans.Reader
import Data.Functor.Identity
main :: IO ()
main = print (runIdentity (runReaderT ask "red"))

Example

import Control.Monad.Trans.Reader
import Control.Monad.Trans.State
import Data.Functor.Identity
main :: IO ()
main = do
  print (runIdentity (runReaderT (do n <- ask; return (n * 2)) 21))
  print (runIdentity (runStateT (do n <- get; put (n + 1); return n) 41))

Key points

  • Transformer: a type that adds one effect to another monad.
  • ReaderT: a transformer that adds a shared read-only value.
  • StateT: a transformer that adds a changeable value.
  • Use lift to run an action from the inner monad inside the outer layer.
  • Run a transformer by peeling its layers in order.

In this example, the first block doubles the shared value 21 to 42, and the second block returns 41 while its state moves to 42. Together they show two different effects layered onto a plain result.

Note

transformers ship with GHC in the transformers library, so no extra install is needed.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Haskell Playground

Exercise

What does a monad transformer do?