[Haskell-cafe] More powerful error handling

Philippa Cowderoy flippa at flippac.org
Sun Feb 17 18:00:18 EST 2008

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 at 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.

More information about the Haskell-Cafe mailing list