
An instance of Monad (Either a) is defined in Control.Monad.Error. Unfortunately, that instance requires the type "a" to be an instance of Error. In fact, using Either for exception handling is only a special case. The Either monad is more generally useful for any complex calculation that needs to exit in the middle and return a value, including multi-level exit. (And no thank you, I would not like to obfuscate my code by using Cont and callCC for that. The Either monad is simple and clean.) It is annoying to work around this problem, since one often has to import Control.Monad.Error. Could this restriction be removed? The Error instance is not used, except to define fail. I don't think it is really important to have a Monad instance where fail references the Error instance; throwError is much more clear. But if others disagree, perhaps a synonym could be used for Either in the context of exceptions. Anyway the namespace there is a bit of a mess; one expects Error to be the non-transforming version of ErrorT, but it is not. How about Throws or Thrown, so I can say: myFun :: a -> b -> c -> Error1 `Thrown` Error2 `Thrown` Error3 `Thrown` ReturnType -Yitz

Hello,
Note: this is shamless plug :-)
I agree with pretty much all you say, except that I tend to think of
the error monad as an abstract type, and not assume that it is the
Either type. This is how things are done in the monad library I
implemented (www.cse.ogi.edu/~diatchki/monadLib). In principle it is
very similar to the library distributed with GHC, so it should be easy
to pick up.
-Iavor
On Sun, 20 Mar 2005 17:03:52 +0200, Yitzchak Gale
An instance of Monad (Either a) is defined in Control.Monad.Error. Unfortunately, that instance requires the type "a" to be an instance of Error.
In fact, using Either for exception handling is only a special case. The Either monad is more generally useful for any complex calculation that needs to exit in the middle and return a value, including multi-level exit.
(And no thank you, I would not like to obfuscate my code by using Cont and callCC for that. The Either monad is simple and clean.)
It is annoying to work around this problem, since one often has to import Control.Monad.Error. Could this restriction be removed?
The Error instance is not used, except to define fail. I don't think it is really important to have a Monad instance where fail references the Error instance; throwError is much more clear.
But if others disagree, perhaps a synonym could be used for Either in the context of exceptions. Anyway the namespace there is a bit of a mess; one expects Error to be the non-transforming version of ErrorT, but it is not. How about Throws or Thrown, so I can say:
myFun :: a -> b -> c -> Error1 `Thrown` Error2 `Thrown` Error3 `Thrown` ReturnType
-Yitz _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

I wrote:
An instance of Monad (Either a) is defined in Control.Monad.Error. Unfortunately, that instance requires the type "a" to be an instance of Error... The Either monad is more generally useful for any complex calculation that needs to exit in the middle and return a value, including multi-level exit... Could this restriction be removed?
Iavor Diatchki wrote:
...I tend to think of the error monad as an abstract type, and not assume that it is the Either type.
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. 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. As an additional option to either (1) or (2), add aliases to Either and ErrorT as a first step to replacing them with better names as Iavor suggests (and does in his alternative monad library). I think that the current situation, in which to do a calculation that is even slightly complex you have to either roll your own monad or use CPS, is not acceptable. I personally prefer (1). -Yitz

Hello,
On Sun, 27 Mar 2005 04:32:37 +0200, Yitzchak Gale
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).
do x <- m; rest ==> m >>= \x -> do rest ,
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 the Monad instances of Either could simply be
instance Monad (Either e) instance Error e => MonadFail (Either e) .
Thomas
participants (3)
-
Iavor Diatchki
-
Thomas Jäger
-
Yitzchak Gale