ReaderT статическая среда
Декларация
ReaderT
преобразователь монад, который добавляет статическую среду к данной монаде.
Что значит добавить статическую среду к данной монаде?
Кто-то предположил, что это дубликат другого вопроса. Я считаю, что этот вопрос уникален, потому что я спрашиваю, что значит иметь статическую среду, а также мой вопрос относится к ReaderT. Даже если это похоже на Reader, они все равно разные.
1 ответ
Это означает, что среда не может быть обновлена: вы можете только читать из нее (отсюда и название ReaderT
). Это в отличие от монадных трансформаторов, таких как StateT
которые предоставляют вам среду, в которую вы можете читать и писать.
Внутри читательской монады вы можете достичь окружения, используя ask
функция:
ask :: Monad m => ReaderT r m r
Внутри государственной монады у вас есть похожая функция для чтения, которая называется get
а также другая функция, которая пишет в состояние под названием put
:
get :: Monad m => StateT s m s
put :: Monad m => s -> StateT s m ()
Примеры
Вот пример использования обоих ReaderT
а также StateT
, Давайте предположим, что моя основная монада будет IO
так что я смогу напечатать вещи по пути.
Придуманный пример - это программа угадывания чисел - среда - это просто число, которое вы пытаетесь угадать (так Int
). guess
берет номер и проверяет, совпадает ли номер с номером в среде. Если нет, то выводит сообщение на экран. В любом случае возвращается, было ли ваше предположение успешным.
guessReader :: Int -> ReaderT Int IO Bool
guessReader guess = do
actual <- ask
if guess == actual
then return True
else do
lift $ putStrLn ("The number was " ++ show actual)
return False
Однако предположим, что теперь вам нужен способ изменения числа, которое вы пытаетесь угадать случайным образом после предположения. Тогда, так как вам нужно изменить среду, вам нужно будет использовать StateT
,
import System.Random (randomRIO)
guessState :: Int -> StateT Int IO Bool
guessState guess = do
actual <- get
if guess == actual
then return True
else do
lift $ putStrLn ("The number was " ++ show actual)
newActual <- lift $ randomRIO (0,10)
put newActual
return False
Затем, если вы запустите версию Reader несколько раз, обратите внимание, что значение, которое вы пытаетесь угадать, никогда не изменится. Это не относится к версии состояния, которая сбрасывается на новый номер каждый раз, когда вы делаете неправильное предположение:
ghci> runReaderT (guessReader 3 >> guessReader 4 >> guessReader 5) 5
The number was 5
The number was 5
True
ghci> evalStateT (guessState 3 >> guessState 4 >> guessState 5) 5
The number was 5
The number was 6
The number was 2
False