
For a while I've been meaning to propose something along the lines of this class: class (MonadError m e, MonadError m' e') => MonadErrorRelated m e m' e' | m -> e, m' -> e', m e' -> m' where catch' :: m a -> (e -> m' a) -> m' a rethrow :: m a -> (e -> e') -> m' a with an example instance being: instance (Error e, Error e') => MonadErrorRelated (Either e) e (Either e') e' where catch' (Right v) _ = Right v catch' (Left e) h = h e rethrow c ef = catch' c (throw . ef) (yep, that definition of rethrow would make a sensible default and there's a default catch' in terms of rethrow too) The nicest use would be for converting between a more specific error type and a more general one that handles a wider range of errors - enabling us to keep tighter track of which errors are possible in a given piece of code. Bonus points for using it together with polymorphic variants where rethrow becomes rather trivial. The following two functions or close variants might also be useful: catchMaybe :: (MonadError m ()) => Maybe a -> m a catchMaybe Nothing = throwError () catchMaybe (Just a) = return a catchEither :: (MonadError m e) => Either e a -> m a catchEither (Left err) = throwError err catchEither (Right a) = return a No doubt there are some names that could use tweaking. As far as I'm concerned you can count me in the camp of people that resent the existing MonadError instances all requiring an Error instance too, it makes things messier when you have access to something like this. But I guess that's because fail is begging for the following definition: fail = fail -- fail is made of fail -- flippa@flippac.org There is no magic bullet. There are, however, plenty of bullets that magically home in on feet when not used in exactly the right circumstances.