
On 15-06-10 03:48 PM, Edward Kmett wrote:
I mentioned in another thread on this topic that it may be perfectly reasonable to extend the class with another method that handles just the pattern match failure case with the details necessary to reproduce the current errors.
class Monad m => MonadFail m where fail :: String -> m a patternMatchFailure :: Location -> CallStack -> Whatever Other Information You Like -> String -> m a patternMatchFailure l w ... = fail (code to generate the string we produce now using the inputs given)
Then a particular concrete MonadFail instance could choose to throw a GHC style extensible exception, it could format the string, it could default to mzero, etc.
I'm +1 on this extension. May I suggest some of Whatever Other Information You Like? I wonder if the following method would be implementable in GHC:
patternMatchFailureOnData :: (Data a, Data b) => Location -> CallStack -> String --^ the fail message -> a --^ the RHS of the failed assignment -> (a -> Maybe b) --^ the failed LHS pattern -> (b -> m c) --^ do continuation -> m a
The method would default to plain patternMatchOnFailure, which would default to fail. It would be invoked on a pattern-match failure iff the type of the RHS has a Data instance in scope. This way an EDSL monad could get some actual use out of the fail mechanism and recover from a failure.
instance MonadFail IO where patternMatchFailure a b c .. = throwIO $ PatternMatchFailure a b c ..
But if we don't capture the location information / string / whatever _somehow_ then we lose information relative to the status quo, just by going down to mzero on a failure. Users use this in their debugging today to find where code went wrong that they weren't expecting to go wrong.
Beyond handling these two "traditional" error cases, I think everything else should be left to something that doesn't infect as central a place as Prelude.
Doing a "general" MonadError with fundeps or without fundeps and just MPTCs still requires you to extend the language of the standard to support language features it doesn't currently incorporate.
Trying to upgrade 'fail' itself to take an argument that isn't just a String breaks all the code that uses -XOverloadedStrings, so if you want more information it is going to have to be in a different method than fail, but it could live in the same class.
Finally fail has different semantics than mzero for important monads like STM that exist today.
-Edward