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

Brian Hulley brianh at metamilk.com
Mon Apr 24 10:25:55 EDT 2006


Brian Hulley wrote:
> I've started work on a module to replace Control.Exception by
> wrapping all the original Control.Exception functions in more general
> monadic functions and using two type classes as follows:
>
> class MonadIO m => MonadException m where
>     catch :: m a -> (Exception -> m a) -> m a
>     catchDyn :: Typeable exception => m a -> (exception -> m a) -> m a
>     catchJust :: (Exception -> Maybe b) -> m a -> (b -> m a) -> m a
>     try :: m a -> m (Either Exception a)
>     tryJust :: (Exception -> Maybe b) -> m a -> m (Either b a)
>
> and
>
> class MonadIO m => MonadIOU m where
>    getUnliftIO :: m (m a -> IO a)
>
> All the other functions can be implemented just using MonadIO or
> MonadIOU or MonadException in place of IO (depending on the function
> eg bracket needs MonadIOU) - just in case anyone is interested.

After more thought, it seems that it *should* be possible to implement block 
and unblock for StateT monads under certain conditions, using a different 
unlift function to return IO (a,s) instead of just IO a. Therefore I've 
changed things around, and also by looking at the source code for the 
current Control.Exception module, arrived at the following revised design 
(I've implemented all the other functions in terms of the classes below)

    class MonadIO m => MonadException m where
        catch :: m a -> (Exception -> m a) -> m a
        catchDyn :: Typeable exception => m a -> (exception -> m a) -> m a
        block, unblock :: MonadException m => m a -> m a

   class MonadIO m => MonadIOU m where
        getUnliftIO :: m (m a -> IO a)

However I then want to say that any instance of MonadIOU is also an instance 
of MonadException. I tried:

    instance MonadIOU m => MonadException m where
        catch action e_m = do
             unliftIOa <- getUnliftIO
             unliftIOb <- getUnliftIO
             liftIO $ C.catch (unliftIOa action) (\e -> unliftIOb(e_m e))
        -- etc

but this only compiles with -fallow-undecidable-instances. I'm puzzled at 
why there is a problem with such a simple instance declaration, and also 
don't know if this means my design is fatally flawed.
The highlight of the above design is that all that's needed for many monads 
such as MonadIOU m => ReaderT r m is a definition of the one unlifting 
function, but it also allows instances of MonadException to be declared 
where the monad (eg a StateT s m) doesn't support this particular operation.

Any ideas?

Thanks, Brian.



More information about the Haskell-Cafe mailing list