
On Mon, Nov 28, 2011 at 1:17 PM, Christian Maeder
Hi,
I was surprised to see my code break with ghc-7, due to changed monad instances:
With ghc-6.12.3 I have:
Prelude> :m Control.Monad.Error Prelude Control.Monad.Error> fail "Bla" :: Either String () Loading package mtl-1.1.0.2 ... linking ... done. Left "Bla"
but with ghc-7.0.4 and ghc-7.2.2 I get a fatal exception:
*Main> fail "Bla" :: Either String () *** Exception: Bla
I always viewed "Either String" as an alternative to Maybe with a failure message.
The instance in ghc-7 comes from Control.Monad.Instances: instance Monad (Either e) where return = Right Left l >>= _ = Left l Right r >>= k = k r
which indeed uses "error" as default implementation of fail. Is there (supposed to be) an overlapping "instance Monad (Either String)" somewhere else?
Any comments (or notes) that I missed?
Cheers Christian
It's not exactly a bug, it's a change in behaviour. Beforehand, there was no overlapping instance, the instance was just 'instance (Error e) => Monad (Either e) where' but the Error constraint proved to be more a hindrance than a help, since it prevented the instance being used with Left things that weren't Errors, even though that's often a useful thing to do. So it was agreed that the Error constraint should be removed, breaking 'fail' but making the instance much more generally applicable. Overlapping instances could be added for individual types, but overlapping instances are usually considered to cause more problems than they solve – ambiguity can easily arise in polymorphic functions over Either. Either still works as Maybe with added information, except now you lose the do-pattern-matching magic. Sometimes I use something like this:
maybe (Left "oh no!") Right $ do x:xs <- Just blah [...]
to use little bits of Maybe inside an Either do. Notice I get control of the error message here, too, so I can usually make it more useful.