
now some details to the discussion: On Tue, 9 Jun 2015, David Luposchainsky wrote:
https://github.com/quchen/articles/blob/master/monad_fail.md
Here's a short abstract:
- - Move `fail` from `Monad` into a new class `MonadFail`.
You think about making MonadFail a subclass of Applicative where the name MonadFail becomes misleading - how about naming it Fail instead?
- - Remove the `String` argument? **No.** The `String` might help error reporting and debugging. `String` may be ugly, but it's the de facto standard for simple text in GHC. No high performance string operations are to be expected with `fail`, so this breaking change would in no way be justified. Also note that explicit `fail` calls would break if we removed the argument.
You know that I am concerned with a strict separation of programming errors and exceptions. "fail" is part of the confusion between the two concepts. If "fail" is inserted by the compiler as desugaring of a pattern match then it gets a compiler generated string as argument. This string refers to program details like source locations and constructor names that have no meaning for the program user. They are intended for debugging, they address the programmer. This implies that "fail" indicates a programming error. In contrast to that, in a monad like Maybe we want to convert a mismatching pattern to Nothing. The compiler generated argument to "fail" does not show up in the Nothing result. This usecase is clearly not for debugging but for regular use in a program. We only want to get the exceptional value Nothing. We should clearly decide what "fail" is intended for - for programming errors or for exceptions. I guess that people want to use it in the second sense, e.g. something like "guard" driven by a pattern match in the Maybe or list monad. But then "fail" must not have an argument because what user related information can the compiler add automatically? Instead of removing the String argument from "fail", the compiler could simply call "mzero" instead. If we want to use "fail" for exceptions then it would be also ok for parser libraries to use it for parser failures. Nonetheless they might be better served with an Except-like monad where they can choose more specific types for the exception messages, e.g. parser errors with source location. In summary I think that the cleanest solution would be to phase out "fail" completely in the long run. But using "mzero" instead of "fail" for monadic pattern matches would alter the proposal considerably. Using "mzero" requires a monad with "mplus" and for support of monads with "mzero" but no "mplus" we need to split MonadPlus, too.