Relax the Either monad

Thomas Jäger thjaeger at gmail.com
Mon Mar 28 08:52:02 EST 2005


Hello,

On Sun, 27 Mar 2005 04:32:37 +0200, Yitzchak Gale <gale at sefer.org> wrote:
> Yes, that would be nice. But I am suggesting this as
> a bug fix. This is a serious problem that makes it very
> awkward to handle a very common case. I am hoping for
> a fix that does not break currently non-broken programs.
> 
> Here are two ways to fix it:
> 
> 1. The bold approach:
>    o Remove the implementation of fail in Monad Either
>    o Remove the Error instance requirement
>    o Possibly move the Monad Either instance to a
>      different module, and just import it in Control.Monad.Error
> 
> That implies that code using fail instead of throwError
> to throw an Error or, worse yet, implicitly throwing an Error with a
> failed pattern match, would be considered already broken.
This would have been the right thing to do in the first place
(assuming no additional compiler support that allowed a sane pattern
matching even if fail was method of a class MonadZero, see below), but
is inacceptable as a library change. It would silently change the
meaning of existing code, and porting from the old to the new
behaviour would be very unreliable if you don't have test cases for
each error condition imaginable.

> 2. The less bold but messier approach: Add a new monad to the
> standard library that looks just like Either, for non-Error
> calculations that need to exit with a value.
Of course, if we had two such monads, one would expect Either to be
the one without an (Error e) constraint, but this definitely sounds
like the lesser of two evils.

3. Compiler support.
Again, this would break existing code (but at least porting is
straightforward) and Haskell 98 compatibility, so consider it as a
suggestion for Haskell 2.
Not all monads support failure, so it is natural to put the fail
method in an additional class MonadZero/MonadFail.
> class Monad m => MonadFail m where
>   fail :: String -> m a
As "x <- m" is very common in do-notation, the translation from the
report now requires a MonadFail constraint (btw, this is exactly what
happens when we use the above MonadFail class in do-notation in ghc
under -fno-implicit-prelude).

If the compiler only used the translation from the report if the
pattern matching was non-exhaustive and in all other cases the more
straightforward translation
> do x <- m; rest    ==>   m >>= \x -> do rest ,
the Monad instances of Either could simply be
> instance Monad (Either e)
> instance Error e => MonadFail (Either e) .


Thomas


More information about the Libraries mailing list