[Haskell-cafe] Correct usage of MonadError, ErrorT?

Andrew Pimlott andrew at pimlott.net
Tue Jan 31 03:05:49 EST 2006

On Tue, Jan 31, 2006 at 05:07:00PM +1300, Daniel McAllansmith wrote:
> On Tuesday 31 January 2006 16:32, Andrew Pimlott wrote:
> > What type would your mapError have?  The first idea that comes to mind
> > is
> >
> >     mapError :: (MonadError e1 m1, MonadError e2 m2) =>
> >                     (e1 -> e2) -> m1 a -> m2 a
> >
> > The problem here is that m1 and m2 have no relation--m1 could be IO and
> > m2 (Either e2)!  Not surprisingly, we can't implement that.  
> Yeah, I expected that would be difficult.
> Is it actually impossible or does it just result in an explosion of code in 
> the implementation, needing a clause to map each instance of MonadError to 
> each other instance on MonadError?
> Not that I'm suggesting that solution, it's just that I'm new to this stuff 
> and don't immediately see why it's impossible (as opposed to impractical).

As Cale said, you can always define your own class that contains some
operation you build mapError on top of.  It might even prove generally
useful.  One idea might be to define a version of MonadError where the
monad can be paramatrized on any error type

    class MonadError' m where
        throwError' :: e -> m e a
        catchError' :: m e a -> (e -> m e a) -> m e a

and see where you get.

> Ok, so mapErrorT, or a convenient wrapper, is the right tool for this 
> situation?
> If so, doesn't using mapErrorT bind the general MonadError class to the 
> specific ErrorT instance?
> So,
> g :: (MonadError String m, MonadIO m) => Int -> m String
> would have to become
> g :: (MonadIO m) => Int -> ErrorT String (m String)
> and that change will propagate out through any function which calls g.

Right.  Note that to use the first signature, g must be written so that
it works for any (MonadError String m, MonadIO m).  But I could define

    instance MonadError String MyMonad where ...
    instance MonadIO MyMonad where ...

that _only_ supports String errors.  You want to call f, which uses Int
errors, from g.  But MyMonad cannot take an Int error, so you're stuck.

I agree that it would be nicer to keep your definition general.  It
doesn't seem possible using MonadError, but maybe with MonadError' or
some other clever idea, you could make it work.

> Is it good advice for a new haskeller to stick to ErrorT in functions with 
> errors?

I'm not sure there's any "common wisdom" about using MonadError.  I
don't get the sense that it's used that much, which seems a bit of a
shame to me.


More information about the Haskell-Cafe mailing list