liveBook · Manning

ReaderT monad

As explained in Functional Design and Architecture: Examples in Haskell

ReaderT is the Haskell monad transformer that adds an immutable environment to an underlying monadic computation.

ReaderT solves a dependency-passing problem: business logic needs an environment of services, but passing a handle through every function creates coupling and noisy interfaces. It stores that handle in an immutable Reader environment surrounding the underlying application monad. section 13.2 section 13.2.3

Define an AppEnv containing service functions, then wrap the application language in ReaderT: type AppRT a = ReaderT AppEnv AppL a. Business logic retrieves the environment with ask and calls underlying AppL actions through lift. section 13.2.3

Injecting an application environment

Construct AppEnv from a reporting channel, run the application with runReaderT meteorsApp appEnv, and unwrap the resulting AppL computation for the framework. This keeps dependency formation at the boundary while the scenario reads services from its context. section 13.2.3

The practical trade-offs are:

  • ReaderT removes the explicit handle from application arguments and supports dependency inversion through an injected environment. section 13.2.3 section 13.3
  • Nested AppRT and AppL layers require lift inside business logic and unwrapping at the application boundary. section 13.2.3
  • The resulting boilerplate may outweigh the benefit, so the simpler Service Handle pattern can be preferable. section 13.2.3
data AppEnv = AppEnv
 { meteorReporter
    :: MeteorTemplate
    -> AppL (Either ReportingError MeteorId)
 , asteroidReporter
    :: AsteroidTemplate
    -> AppL (Either ReportingError AsteroidId)
 }

Browse the AppEnv definition to see how reporting dependencies are represented as functions returning AppL computations. section 13.2.3

Listing 13.9 DIP-compliant code with ReaderT
meteorsApp :: AppRT ()
meteorsApp = do
  AppEnv reporter _ <- ask                            #1
  
  eResult <- lift (reporter (MeteorTemplate 1 1 1 1)) #2
  case eResult of
    Right meteorId -> ...
    Left err       -> ...

Browse the complete ReaderT scenario to see ask retrieve the environment and lift invoke an underlying AppL action. section 13.2.3

How Functional Design and Architecture: Examples in Haskell covers it

How deep it goes
Explains environment definition, layered execution, ask, lift, and boundary unwrapping, then stops short of reducing boilerplate.
Examples
Demonstrates AppEnv, meteor reporting, ask, lift, runReaderT, and runtime injection through a reporting application.
What it assumes
Assumes familiarity with Haskell monads and monad transformers while teaching dependency injection through a service environment.
What you can do after
Apply it by defining an environment, retrieving dependencies with ask, lifting underlying actions, and running the scenario with runReaderT.
How it connects
Connects ReaderT to dependency inversion, the Service Handle pattern, StateT, monad transformers, and AppL.

Also explained in

Compare how 2 books explain ReaderT monad →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Design and Architecture: Examples in Haskell. The section links point to the parts of the book it draws on.