Richard Silverman wrote:
> I'm puzzled by something. Suppose I have some code that does lots of IO,
> and also occasionally refers to some global state. No problem, use
> ReaderT for the state, combining with the IO monad. Except... since IO
> is on the bottom, simple uses of do-notation such as "foo <- ask" work
> in the Reader monad, and to access the IO monad, I need to lift, e.g.
> (bar <- liftIO getLine). If my code does lots of IO, this is *very* ugly
> -- the code is littered with lift functions! Is there no cleaner way to
> do this?
Not that I know of. However, you can usually group IO-statements
together in one bigger block:
blah = do
foo <- ask
biz <- liftIO $ do
meep
bop foo
bleep foo
zap biz
etc.
And if there is a limited number of specific functions you need to lift
often, you can write generalised MonadIO-based versions of these so that
you can call them directly from the monad transformer:
getLine :: MonadIO m => m String
getLine = liftIO SystemIO.getLine
Assuming an appropriate MonadIO instance of ReaderT, of course.
Does that help?
Martijn.