MonadIO and IO exceptions

Yitzchak Gale gale at
Sat Feb 2 18:27:44 EST 2008

Judah Jacobson wrote:
> I've already demonstrated how a library writer can solve that problem in:

Yes, that is indeed very nice. But I don't think it is
a practical solution right now, for the following reasons:

It requires that users be in a special monad; it doesn't
work for regular MonadIO. So it isn't really a practical
solution until it gets into MTL and people start porting
their code.

Providing an instance for MonadIO1 (or whatever we would
call it) is an extra step for monad writers that may
often be skipped.

Also, there are obviously many other more complex
cases beyond a simple bracket. How general is this
technique? As you point out, even for bracket it does
not work unless the "after" action is IO. What other
restrictions are there in the general case?

Perhaps we could fix those problems by also providing
liftIOk for all kinds k that occur in the signatures of various
functions in Control.Exception. But that would make the new
monad even more unwieldy.

As I suggested before, I think the best solution would
be to define the functions of Control.Exception
in terms of lower-level primitives that could then be
used to define the functions directly for other monads.

Perhaps something like this would be general
enough to cover everything:

-- Delay any exception and put in buffer
startDelayingExceptions :: IO ()

-- Stop delaying exceptions
stopDelayingExceptions :: IO ()

-- Retrieve delayed exception and clear buffer
getDelayedException :: IO (Maybe Exception)

There would be one exception buffer per thread.
New exceptions would replace old ones, so users
of this mechanism would be required to catch as
catch can.

Based on Simon Marlow's observation in our previous
discussion on this topic, we would still want to leave
around the current primitives as a special case
optimization for IO.


More information about the Libraries mailing list