MonadReader, MonadWriter and MonadState classes have fundeps from the
monad type to the environment / output / state type (I added them
a few months ago).
MonadError doesn't. I thought that it's desirable to make a class with
more than one exception type, such that for example each catchError
would catch the corresponding throwError only, or even with simulation
of some subtyping policy.
Now I'm not sure that it was the right choice. I have an example when
having this fundep would be very helpful:
I am experimenting with building monadic parsing combinators from monad
transformers. In particular I already have a Parsec-like parsing monad
composed from pieces. It would be bad to hardwire the error type.
But without a fundep in MonadError overloaded functions can't be
written with MonadError in the context and without mentioning the
error type in their type (which would be impractical).
My workaround is to have a separate class, similar to MonadError but
with a fundep, with MonadError in its superclass, and with its own
instances. Fortunately this class can be empty, taking implementation
of pushing the error handling through monad transformers from
MonadError. But it would be more straightforward to use MonadError
directly.
I make use of the fundep in MonadState too. So I think that usually
one wants these fundeps.
Other argument for having a fundep in MonadError: monad transformers
provided by modules in package lang don't provide a monad which
could handle multiple errors anyway, and it would be impossible to
do it generically without overlapping instances. An instance would
have to recognize "its" error type, so it must work on a hardwired
type constructor.
If there was a fundep, the behavior of different error types can be
simulated by providing functions defined in terms of throwError and
catchError which throw a specific type or catch only a specific type
(this works only in the case where handling of all errors is done at
the same level of monad transformers, but I doubt that anyone would
make a monad without this property and still wanted to use generic
throwing and catching functions). This can be even done generically in
terms of classes which coerce a specific error type up or recognize
it, without touching all monads, as I am doing in the workaround in
the opposite direction.
What do you think? If nobody answers, I think I will add the fundep...
BTW, another question: should MonadPlus instead of just Monad be
a superclass of MonadError? It has a natural definition in terms
of catchError.
--
__("< Marcin Kowalczyk * qrczak@knm.org.plhttp://qrczak.ids.net.pl/
\__/
^^ SYGNATURA ZASTĘPCZA
QRCZAK