I am new at haskell, I have to write a program context-aware,so I thought I can use the Reader Monad for keeping the context read from a file, I know how to read the file p
I think it's easiest if you look at how you would solve this problem without using Reader, then compare the translated version. Here's a trimmed-down example from a program I'm working on where the environment is a set of callback functions to update the display. It's slightly more complicated because it uses ReaderT instead of Reader, but everything works in basically the same way.
runProcess :: Env -> State -> Action -> IO State
runProcess env state action = do
newstate <- processAction state action
let ufunc = mainUFunc env -- get the callback to update the display
ufunc newstate -- update the display
return newstate
Now I'll change it to use the Reader monad to pass along the environment. Since the code was already in IO, it's necessary to use the monad transformer version, ReaderT
.
runProcessR :: State -> Action -> ReaderT Env IO State
runProcessR state action = do
newstate <- lift $ processAction state action
env <- ask -- get the environment from the reader
liftIO $ (mainUFunc env) newstate -- updating is in IO; it needs to be lifted
return newstate
At this point, the program's main loop will essentially be:
loop :: State -> ReaderT Env IO ()
loop = do
action <- liftIO getAction
if action == EndLoop
then return ()
else do
st' <- processActionR st action
loop st'
mainLoop :: IO ()
mainLoop = do
env <- setUpCallbacks
let st = initState
runReaderT $ loop st
So that's how you can use Reader. Every function that used to take an environment parameter no longer needs to. Functions that don't take the environment can be used directly or lifted if they're monadic.