
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.

On Sun, 17 Feb 2008, Philippa Cowderoy wrote:
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.
I guess it's about exception handling, not error handling, right? I thought that must be possible by plugging various exception types together, say data CustomException = IOExc IOError | NetworkExc NetworkException | ThreadExc ThreadingException Now you can turn any IOError to CustomException by wrapping it with IOExc.
participants (2)
-
Henning Thielemann
-
Philippa Cowderoy