What is the purpose of the reader monad?¶
This blog answered the question of What is the purpose of the reader monad? in my view. The original answer stays on stackoverflow.
I have learned much from the above answers, and thanks them for answering. Although I'm new to Haskell, I want to say something about the Reader
monad.
First, treating a Reader as a Computation
is important. It's not a state, but a computation. For example, the function calc_isCountCorrect
mentioned in first official example of Reader monad returns a Reader Bindings Bool
, which means it receives a Bindings
when runReader
, and return a Bool. It's a computation.
calc_isCountCorrect :: Reader Bindings Bool
calc_isCountCorrect = do
count <- asks (lookupVar "count")
bindings <- ask
return (count == (Map.size bindings))
You can also pass the Bindings
through an argument, there is no significant differences when your code is quite simple.
calcIsCountCorrectWithoutReader :: Bindings -> Bool
calcIsCountCorrectWithoutReader bindings = do
let num = lookupVar "count" bindings
let count = Map.size bindings
num == count
However, it does have a difference, that's where the value comes from
. It gives you a way to retrieve it by an implicit source instead of an argument.
When it comes to the question of analogy, I think the lambda
in C++
is a good explanation.
In an imperative language like Java or C++, there is no equivalent concept for the reader monad.
The reader gives you abilities to retrieve a value from outside(NOT global variable, but an upper scope). It's pretty like a capture clause in C++ lambda
.
For example, you have a haskell code that trebles number
and adds it with an implicit value. The following code outputs 10
.
import Control.Monad.Reader
trebleNumberAndAddImplicitly :: Int -> Reader Int Int
trebleNumberAndAddImplicitly number = do
implicitNumber <- ask
return $ 3*number + implicitNumber
main :: IO ()
main = do
print $ runReader (trebleNumberAndAddImplicitly 3) 1
The implicit value is outside the COMPUTATION but accessible with Reader
.
Inside C++, this is called capture clause
. The output is: output is: 10
. However, it has more limitations than haskell. But it's similar in my mind.