Search code examples
haskellreader-monad

What is "a function that you call" and what is "a function that call you"?


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 of r for functions that you call, but not for functions that call you. The best way to demonstrate this is with the withReaderT function which lets us start a new Reader 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"?


Solution

  • 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"