Reader Monad

Suppose we have a function that requires knowing the environment

start :: Env -> ...

It will be pretty common to require this throughout the code.

startLogger :: Env -> ...
startDatabase :: Env -> ...

Considering that we only need read access to the environment, we can use the reader monad

data Reader r a = Reader (r -> a)

instance Monad (Reader r) where
    return a = ReaderG $ \_ -> a
    (>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
    ReaderG f >>= g = ReaderG $ \r -> let a = f r
                                          f' = g a
                                       in f' r

Observe that the variable r passed into both functions f, f' is the same.

This shows that we reuse the same r value, which could be the environment, a configuration and so on.

This is used as a READ-only value. We cannot update it, as again (>>=) only gives us a.

This allows us to do things like the following

-- Get environment
ask :: Reader r r

-- Modify local environment
local :: (r -> r) -> Reader r a -> Reader r a

main :: Reader r r
main = do
  r <- ask -- ^ Access to the `r` value
  return r
  
-- equivalent to 
main2 :: Reader r r
main2 = ask >>= \r -> return r -- ^ return expanded here for similarity with main

What if we want both READ/WRITE?

We can use the State Monad which combines the ideas of the Reader and Writer monads

References: hackage