I'm trying to understand what is Haskell Reader monad, but I struggle with this part in the book:
The “read-only” nature of the type argument
r
means that you can swap in a different type or value ofr
for functions that you call, but not for functions that call you. The best way to demonstrate this is with thewithReaderT
function which lets us start a newReader
context with a different argument being provided:withReaderT :: (r' -> r) -- ^ The function to modify the environment. -> ReaderT r m a -- ^ Computation to run in the modified environment. -> ReaderT r' m a
So, first of all, could you please specify what to consider "a function that you call" and what to consider "a function that call you"?
I think this is just an English language misunderstanding. When it says "you", it just means "the code you are currently concerned with".
If you are writing a function myfunction
:
myfunction x y = sqrt (x*x + y*y)
main = print $ myfunction 3 4
If we say that you are myfunction
, then sqrt
is a function that you call, and main
is a function that calls you.
The point the book is trying to make is that your code can call functions with any environment you want, but those functions can not change the environment for your code. In turn, code that calls your code can specify any environment it wants you to see, but you can not change the environment for that code.
Here's a commented example:
import Control.Monad.IO.Class
import Control.Monad.Trans.Reader
import Control.Monad.Trans
showValue :: String -> ReaderT String IO ()
showValue str = do
s <- ask
lift . putStrLn $ str ++ ": " ++ s
-- This is me (i.e. my code).
-- I show the environment twice, and it's guaranteed to be the same both times
myFunction :: ReaderT String IO ()
myFunction = do
showValue "myFunction sees"
withReaderT (const "Something Completely Different") functionThatICall
showValue "myFunction still sees"
-- This is a function that I call.
-- I decide what value it sees, but it can't decide what I see.
functionThatICall :: ReaderT String IO ()
functionThatICall = showValue "functionThatICall sees"
-- This is a function that calls me. It decides what value I see,
-- but I can't change what it sees.
functionThatCallsMe :: ReaderT String IO ()
functionThatCallsMe = do
showValue "functionThatCallsMe sees"
myFunction
showValue "functionThatCallsMe still sees"
main = runReaderT functionThatCallsMe "Hello World"
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