[Haskell-cafe] combining monads with IO

wren ng thornton wren at freegeek.org
Thu Jun 25 19:42:47 EDT 2009


Richard Silverman wrote:
> 
> Hi all,
> 
> 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?

Depending on the exact structure of your program, embracing imperativism 
may help. That is, you can use IORefs (or STRefs, or...) to store your 
global state instead of using StateT. Sometimes it helps, sometimes not; 
it depends a lot on the structure of the state, how fond you are of 
combinators, how you want to pass the IORefs down to the combinators,...


The cleanest approach to issues like this is usually to wrap a newtype 
wrapper around your specialty monad and use -XGeneralizedNewtypeDeriving 
to hoist all the layers up to the top. Or if you want to ensure 
portability then you can hand-write all the boilerplate instances for 
MonadFoo MyMonad. Depending on how you use IO, you'll want to mix this 
with judicious use of liftIO or define some wrappers or a typeclass for 
lifting your common IO functions to work on MyMonad.

-- 
Live well,
~wren


More information about the Haskell-Cafe mailing list