(un-)deprecation of Control.Monad.Error
Add Reply
Paterson, Ross
2018-10-29 16:40:28 UTC
I'm unhappy about the current state of Control.Monad.Error; the module
Use "Control.Monad.Except" instead
However, Control.Monad.Except implements 'fail' as an error, inheriting
the behavior of Identity. To my mind the whole point of
Control.Monad.Error is that it replicates the old non-error behavior of
`fail` that the Either type and EitherT used to have.
I think that fail on Either or EitherT has always been the default (error).
The situation is similar with the MonadFail class; there is are
instance (Monad m, Error e) => MonadFail (ErrorT e m)
instance MonadFail m => MonadFail (ExceptT e m)
which means that Except doesn't have a MonadFail instance,
because Identity has none, whereas ErrorT implements a non-error
version of `fail`.
The principal flaw of ErrorT is that the monad methods had constraints
on the exception type, even though they don't need them. (A lesser
issue was that the naming was inconsistent with the other transformers.)

One possibility would be to change the MonadFail instance for ExceptT
to give the functionality of the ErrorT instance:

instance (Monad m, Message e) => MonadFail (ExceptT e m)

(If it is decided in the other thread to have a non-default MonadFail
instance for Either, it would make sense to use that class here.)

Then, for base >= 4.9:
- there would be a MonadFail instance for ExceptT ... Identity
- the MonadFail instances for monads based on [], Maybe and IO would have
the constraint on the exception type, and different behaviour.

That would be awkward, but seems preferable to having two very similar
but slightly different transformers.