I would like to learn, how to use the Reader Monad. Unfortunately only a small amount of example code is available
I would like to create a Reader, where the environment and the retrived values are Int
. I defined the type like this:
type IntRead = Reader Int Int
The code I tried is this:
addStuff :: Reader Int Int
addStuff = do
a <- (*2)
b <- (+10)
return (a+b)
I get an error, because ReaderT
is expected. How to create a function like addStuff
using the Reader Monad? Where should I provide the environment to this function?
You can convert functions to readers and back with these two isomorphisms:
reader :: (r -> a) -> Reader r a
runReader :: Reader r a -> r -> a
E.g.
addStuff :: Reader Int Int
addStuff = do
a <- reader (*2)
b <- reader (+10)
return (a+b)
and then you can test your code with runReader addStuff 5
.
This is OK for learning purposes. For more serious code, you shouldn't use the isomorphisms that much, but instead rely on ask
or asks
. E.g.
addStuff :: Reader Int Int
addStuff = do
x <- ask -- fetch the implicit Int value
let a = (*2) x
b = (+10) x
return (a+b)
or, better
addStuff :: Reader Int Int
addStuff = do
a <- asks (*2) -- fetch the implicit Int value, and apply the function
b <- asks (+10)
return (a+b)
or, even better, using applicative style:
addStuff :: Reader Int Int
addStuff = (+) <$> asks (*2) <*> asks (+10)
The whole point of the reader abstraction is not to think about the underlying function. You can just pretend to have access to a read-only variable, which is accessible through the ask
primitive.
Usually, only at the very last step you use runReader
to actually use your monadic reader action.