问题
Declaration of the
ReaderT
monad transformer, which adds a static environment to a given monad.
What does it mean to add a static environment to a given monad?
Someone suggested that this is a duplicate to another question. I believe that this question is unique because I'm asking what it means to have a static environment and also my question pertains to ReaderT. Even if it is similar to Reader, they are still different.
回答1:
It means that the environment cannot be updated: you can only read from it (hence the name of ReaderT
). This is in contrast to monad transformers like StateT
which provide you an environment you can both read and write to.
Inside a reader monad, you can reach the envionment using the ask function:
ask :: Monad m => ReaderT r m r
Inside a state monad, you have a similar function for reading called get as well as another function which writes to the state called put:
get :: Monad m => StateT s m s
put :: Monad m => s -> StateT s m ()
Examples
Here is a sample usage of both ReaderT
and StateT
. Let's suppose my underlying monad will be IO
so that I will be able to print things along the way.
The contrived example here is a number guessing program - the environment is just a number that you are trying to guess (so Int
). guess
takes a number and checks whether the number is the same one as the one in the environment. If not, it prints a message to the screen. In either case, it returns whether your guess was successful.
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
However, suppose now you want a way of changing the number you are trying to guess randomly after a guess. Then, since you need to change the environment, you will need to use 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
Then, if you run the reader version several times, note that the value you are trying to guess never changes. That is not the case with the state version, which resets to a new number every time you make a wrong guess:
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
来源:https://stackoverflow.com/questions/40066909/readert-static-environment