
On Mon, Jan 5, 2009 at 2:13 PM, Luke Palmer
wrote: On Mon, Jan 5, 2009 at 1:48 PM, Peter Robinson
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) monads.
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 differentiating 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! Peter