[Haskell-cafe] Re: Control.Exceptions and MonadIO

Brian Hulley brianh at metamilk.com
Sun Apr 23 14:19:18 EDT 2006


oleg at pobox.com wrote:
> Robert Dockins wrote:
>> One additional (very unfortunate) point is that higher-order IO monad
>> combinators will not work on your monad, eg, the ones in
>> Control.Exception.
>
> Although that is true in general, for many useful and interesting
> cases (including ReaderT, the state transformer, and the newtype
> wrapping of IO) one _can_ use catch, bracket etc. constructs in
> MonadIO. Please see this message and the follow-up discussion:
>
> http://www.haskell.org/pipermail/haskell/2006-February/017547.html

If it is true that it is absolutely impossible to implement 
Control.Exception for any MonadIO (it would be useful to know why cf the old 
saying "there is no such word as can't"), the other option seems to be to 
re-organise Control.Exception to make use of different monads that could 
support the various subsets of operations, as you've begun in the thread 
above by defining CaughtMonadIO.

Perhaps something like:

class MonadIO m => MonadIOE m where
     catch :: m a-> (Exception -> m a) -> m a
     throw
     catchDyn
     throwDyn
     -- etc

instance MonadIOE m => StateT s m where ...
instance MonadIOE m => ReaderT r m where ...

blockIO :: IO a -> IO a

class MonadIO m => MonadIOB m where
     getUnliftIO :: m (m a -> IO a)
     block :: m a -> m a
     block x = do
                        unliftIO <- getUnliftIO
                        liftIO (blockIO (unliftIO x))

     unblock :: m a -> m a
     bracket_ :: m a -> m b -> m c -> m c
     -- etc

instance MonadIOB m => ReaderT r m where ...

and then we could just get rid of all the other exception handling functions 
scattered all over the code base eg Prelude.catch etc.

StateT s can be an instance of MonadIOE but not of MonadIOB because although 
it is sometimes fine to discard state changes when an exception arises, it 
is not ok to discard the state changes inside a block (or unblock, bracket_ 
etc).

Does the above look like a good way of organising things?
(I don't know whether MonadIOB would require MonadIOE or not since I haven't 
tried to implement all these functions yet - if it did I would use the name 
MonadIOEB instead)
I'm about to make an attempt along these lines myself since I can't go 
further in my own work without a proper exception api that doesn't drag 
everything down to concrete IO (unless someone else has already done this?)
Also, would it be worth modifying 
http://hackage.haskell.org/trac/haskell-prime/ticket/110 to include 
something like this (someone more knowledgeable than me would have to do 
it)?

Regards, Brian.



More information about the Haskell-Cafe mailing list