[Haskell-cafe] Portability of MonadError

Peter Robinson thaldyron at gmail.com
Mon Jan 5 16:44:29 EST 2009

> On Mon, Jan 5, 2009 at 2:13 PM, Luke Palmer <lrpalmer at gmail.com> wrote:
>> On Mon, Jan 5, 2009 at 1:48 PM, Peter Robinson <thaldyron at gmail.com>
>> wrote:
>>> Hello,
>>> One thing that's been bothering me about MonadError monads is
>>> the non-portability of code that uses a custom Error type.  Meaning, if I
>>> have libraries A and B that use different error types, I won't be able to
>>> write a function func:
>>> func = (funcA >> funcB) `catchError` (\e -> ...)
>>> funcA :: ErrorT MyErrorA m ()
>>> funcB :: ErrorT MyErrorB m ()
>>> So I'm wondering whether there's a reason not to introduce a type class
>>> hierarchy instead of custom error types to make the code more portable.
>> I think this worry is related to a world view of "large monads", which
>> also proliferates claims like "monads are not appropriate for large
>> programs", and is related to fat interfaces in OOP.  I claim that, like
>> objects, monads are appropriate for little pieces of computations, and
>> monadic computations in different monads deserve to be composed just as much
>> so as those in the same monad.

Well my main concern was that composability issue of "similar" (modulo
error type)

>> The complex type-directed approach gives the feel of exceptions from
>> mainstream languages, but will run into problems when eg. two computations
>> both use ErrorT String, but you want to differentiate the errors.

Not sure I got this: When using the type class approach you would not use
an instantiation like ErrorT String in code intended to be portable, but rather
something like "ErrorT MyClass". Either two computations have the same
error type class or they don't, so there shouldn't be any problem
errors, right?

>> All that
>> is necessary is a simple function:
>> mapError :: (e -> e') -> ErrorT e a -> ErrorT e' a
>> mapError f = ErrorT . liftM (left f) . runErrorT
> Modulo obvious errors, as usual.  Haskell type inference knows better than I
> do:
> mapError :: Monad m => (e -> e') -> ErrorT e m a -> ErrorT e' m a
> Luke
>> (Where "left" is from Control.Arrow, and is a "semantic editor")
>> Then your example can become::
>> func = (mapError Left funcA >> mapError Right funcB) `catchError` (\e ->
>> ...)

Yes that does look interesting. Thanks for the hint!


More information about the Haskell-Cafe mailing list