简体   繁体   中英

Combining ReaderT monads?

It seems that it would be useful to be able to combine different ReaderT environments.

For instance, a generic logging facility might look something like this:

logit :: Text -> ReaderT Bool  IO ()
logit str = do debugflag <- ask
               liftIO $ if debugflag then putStrLn ("debug: " ++ str) else return ()

This looks like a nice reusable component. So how would I go about integrating this definition with another ReaderT environment so that I could use both of them?

For instance, suppose I want to combine it with this ReaderT instance:

foo :: ReaderT Text IO ()
foo = ...

so that I can use both foo and logit in the same function.

You'll want to layer them into a stacked monad, but they can't be stacked together since both of them declare that IO is exactly the wrapped monad. Fortunately, your code is already general enough to lift this restriction. The most general types of your functions use MonadIO instead of specifically using IO . If you change the types to

 logit :: MonadIO m => Text -> ReaderT Bool m ()
 foo   :: MonadIO m =>         ReaderT Text m ()

then the liftIO call will lift the IO actions through the entire stack to an IO monad at the bottom.

To be clear, the types you've written do not need to use liftIO —the same type would be satisfied by just lift , but since IO is (trivially) an instance of MonadIO then your (overly) specialized type will also pass the checker.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM