I am trying to understand when to use the reader monad, but I haven’t found a good usage example. I am pretty sure I have limited knowledge on this topic.
Consider this example code:
import Control.Monad.Reader
data Env = Env
{ eInt :: Int
, eStr :: String
}
calculateR :: Reader Env Int
calculateR = do
e <- ask
return $ eInt e
calculate :: Env -> Int
calculate = eInt
main :: IO ()
main = do
let env = Env { eInt = 1, eStr = "hello"}
let a = runReader calculateR env
let b = calculate env
print (a,b)
If I want to pass around the global Env
to be able to access it from any function, should I use the reader monad for this purpose?
In comparison to just passing the Env
directly to the function, is there any benefit?
If I understand correctly, both calculate
and calculateR
are pure (in the sense that they won't be able to make any change to env
), and both have Env
in their type signature telling that they might read the value form env
to use in their computation.
The advantage comes when you want to compose two functions.
f :: a -> Reader Env b
g :: b -> Reader Env c
g <=< f
or in the do
notation
\a -> do
b <- f a
g b
vs
f :: a -> Env -> b
g :: b -> Env -> c
\a e -> g (f a e) e
in the latter you have to keep passing the environment around by yourself, while the monad instance provides you with a composition that does it for you. The manual composition will quickly become unnecessarily verbose and complex as more functions are involved.
Reader then provides you with local
too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With