Что такое «функция, которую вы вызываете» и что такое «функция, которая вызывает вас»? - PullRequest
4 голосов
/ 20 июня 2020

Я пытаюсь понять, что такое Haskell монада Reader, но мне не нравится эта часть книги:

Природа аргумента типа «только для чтения» r означает, что вы можете поменять местами другой тип или значение r для функций, которые вы вызываете, но не для функций, которые вас вызывают. Лучший способ продемонстрировать это - использовать функцию withReaderT, которая позволяет нам запустить новый контекст Reader с другим аргументом:

withReaderT 
  :: (r' -> r) 
  -- ^ The function to modify the environment. 
  -> ReaderT r m a 
  -- ^ Computation to run in the modified environment. 
  -> ReaderT r' m a 

Итак, прежде всего, не могли бы вы укажите, что считать «функцией, которую вы вызываете», а что считать «функцией, которая вызывает вас»?

1 Ответ

9 голосов
/ 20 июня 2020

Я думаю, что это просто недоразумение английского sh языка. Когда он говорит «вы», это просто означает «код, который вас интересует в данный момент».

Если вы пишете функцию myfunction:

myfunction x y = sqrt (x*x + y*y)
main = print $ myfunction 3 4

Если мы говорим, что вы - это myfunction, тогда sqrt - это функция, которую вы вызываете, а main - это функция, которая вас вызывает.

Суть книги заключается в том, что ваш код может вызывать функции с любыми среда, которую вы хотите, но эти функции не могут изменить среду для вашего кода. В свою очередь, код, вызывающий ваш код, может указать любую среду, которую он хочет, чтобы вы видели, но вы не можете изменить среду для этого кода.

Вот пример с комментариями:

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