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.

_______________________________________________
Haskell-Cafe mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to