<div dir="ltr"><div><font face="monospace, monospace">I'm a really big fan of Edward's `patternMatchFailure` suggestion. It's clear, useful and has an obvious name. (The fact that `fail` is related to pattern matching is by no means obvious!)<br><br></font></div><font face="monospace, monospace">It also moves the class even further away from Monad, at least conceptually, so I think a more generic naming convention and possibly fairly relaxed superclass requirements make sense.<br></font></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jun 10, 2015 at 12:48 PM, Edward Kmett <span dir="ltr"><<a href="mailto:ekmett@gmail.com" target="_blank">ekmett@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">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.<span class=""><div><br></div><div><font face="monospace, monospace">class Monad m => MonadFail m where</font></div><div><font face="monospace, monospace"> fail :: String -> m a</font></div></span><div><font face="monospace, monospace"> patternMatchFailure :: Location -> CallStack -> Whatever Other Information You Like -> String -> m a</font></div><div><font face="monospace, monospace"> patternMatchFailure l w ... = fail (code to generate the string we produce now using the inputs given)</font></div><div><br></div><div>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.</div><div><br></div><div><font face="monospace, monospace">instance MonadFail IO where</font></div><div><font face="monospace, monospace"> patternMatchFailure a b c .. = throwIO $ PatternMatchFailure a b c ..</font></div><div><br></div><div>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.<br></div><div><br></div><div>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.</div><div><br></div><div>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.</div><div><br></div><div>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.</div><div><br></div><div>Finally fail has different semantics than mzero for important monads like STM that exist today.</div><span class="HOEnZb"><font color="#888888"><div><br></div><div>-Edward</div></font></span></div><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jun 10, 2015 at 6:07 PM, David Feuer <span dir="ltr"><<a href="mailto:david.feuer@gmail.com" target="_blank">david.feuer@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">But why does a string actually make sense in the context of handling<br>
pattern match failures? Sticking to a Haskell 98 solution, I would<br>
think MonadZero would be the way to go for those, rather than<br>
MonadFail. What, after all, can you really do with the string<br>
generated by a pattern match failure? For everything other than<br>
pattern match failures, I would think the user should use MonadError,<br>
a non-fundep MonadError, or just work directly without classes.<br>
<div><div><br>
On Wed, Jun 10, 2015 at 11:53 AM, Edward Kmett <<a href="mailto:ekmett@gmail.com" target="_blank">ekmett@gmail.com</a>> wrote:<br>
> You could handle that case explicitly by giving a class that converted a<br>
> string into e and putting that constraint on the MonadFail instance for<br>
> Either:<br>
><br>
> class Error a where<br>
> strMsg :: String -> a<br>
><br>
> instance Error e => MonadFail (Either e) where<br>
> fail = Left . strMsg<br>
><br>
> We used to do this in the mtl, with the Error class, but it then had to<br>
> encumber the entire Monad, so even folks who didn't want it needed to supply<br>
> a garbage instance.<br>
><br>
> Right now, fail for Either is necessarily _error_ because we can't put it in<br>
> the left side without incurring a constraint on every user of the monad.<br>
><br>
> At least here the ad hoc construction can be offloaded to the particular<br>
> MonadFail instance, or to whatever monad someone makes up for working with<br>
> their Either-like construction.<br>
><br>
> -Edward<br>
><br>
> On Wed, Jun 10, 2015 at 5:44 PM, David Feuer <<a href="mailto:david.feuer@gmail.com" target="_blank">david.feuer@gmail.com</a>> wrote:<br>
>><br>
>> My main concern, I suppose, is that I don't see a way (without<br>
>> extensions) to deal with even the most basic interesting failure<br>
>> monad: Either e. It therefore seems really only to be suitable for<br>
>> pattern match failure and user-generated IOErrors, which don't really<br>
>> strike me as terribly natural bedfellows.<br>
>><br>
>> On Wed, Jun 10, 2015 at 10:55 AM, Edward Kmett <<a href="mailto:ekmett@gmail.com" target="_blank">ekmett@gmail.com</a>> wrote:<br>
>> > This would require you to add MPTCs to the language standard, which<br>
>> > means<br>
>> > standardizing how they work.<br>
>> ><br>
>> > Any solution involving SomeException or any of its variants is going to<br>
>> > drag<br>
>> > in GADTs, Typeable, higher rank types.<br>
>> ><br>
>> > ... and it would drag them inexorably into the Prelude, not just base.<br>
>> ><br>
>> > Compared to a simple<br>
>> ><br>
>> > class Monad m => MonadFail m where<br>
>> > fail :: String -> m a<br>
>> ><br>
>> > that is a very hard sell!<br>
>> ><br>
>> > On the other hand, I do think what we could do is add more information<br>
>> > about<br>
>> > pattern match failures by adding another member to the class<br>
>> ><br>
>> > class Monad m => MonadFail m where<br>
>> > patternMatchFailure :: Location -> String -> whatever else you like -><br>
>> > m a<br>
>> > patternMatchFailure l s ... = fail (code to generate the string we<br>
>> > generate in the compiler using just the parts we're passed)<br>
>> ><br>
>> > fail :: String -> m a<br>
>> ><br>
>> > Then the existing 'fail' desugaring could be done in terms of this<br>
>> > additional member and its default implementation.<br>
>> ><br>
>> > This remains entirely in the "small" subset of Haskell that is well<br>
>> > behaved.<br>
>> > It doesn't change if we go and radically redefine the way the exception<br>
>> > hierarchy works, and it doesn't require a ton of standardization effort.<br>
>> ><br>
>> > Now if we want to make the fail instance for IO or other MonadThrow<br>
>> > instances package up the patternMatchFailure and throw it in an<br>
>> > exception we<br>
>> > have the freedom, but we're avoid locking ourselves in to actually<br>
>> > trying to<br>
>> > figure out how to standardize all of the particulars of the exception<br>
>> > machinery into the language standard.<br>
>> ><br>
>> > -Edward<br>
>> ><br>
>> > On Wed, Jun 10, 2015 at 4:19 PM, David Feuer <<a href="mailto:david.feuer@gmail.com" target="_blank">david.feuer@gmail.com</a>><br>
>> > wrote:<br>
>> >><br>
>> >> Here's a crazy question: would a version of MonadError without the<br>
>> >> fundep do the trick?<br>
>> >><br>
>> >> class Monad m => MonadFail e m where<br>
>> >> fail :: e -> m a<br>
>> >><br>
>> >> instance MonadFail a [] where<br>
>> >> fail = const []<br>
>> >><br>
>> >> instance (a ~ e) => MonadFail e (Either a) where<br>
>> >> fail = Left<br>
>> >><br>
>> >> instance MonadFail SomeException IO where<br>
>> >> fail = throwIO<br>
>> >> instance MonadFail IOException IO where<br>
>> >> fail = throwIO<br>
>> >> ...<br>
>> >> instance MonadFail String IO where<br>
>> >> fail = throwIO . userError<br>
>> >><br>
>> >> On Wed, Jun 10, 2015 at 8:32 AM, Mario Blažević <<a href="mailto:blamario@ciktel.net" target="_blank">blamario@ciktel.net</a>><br>
>> >> wrote:<br>
>> >> > +1 from me.<br>
>> >> ><br>
>> >> > A minor nitpick: the proposal should clarify which of the<br>
>> >> > existing<br>
>> >> > instances of Monad from base get a MonadFail instance. My<br>
>> >> > understanding<br>
>> >> > is<br>
>> >> > that none of them would define fail = error, but that has not been<br>
>> >> > made<br>
>> >> > explicit.<br>
>> >> ><br>
>> >> ><br>
>> >> > _______________________________________________<br>
>> >> > Libraries mailing list<br>
>> >> > <a href="mailto:Libraries@haskell.org" target="_blank">Libraries@haskell.org</a><br>
>> >> > <a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries</a><br>
>> >> _______________________________________________<br>
>> >> Libraries mailing list<br>
>> >> <a href="mailto:Libraries@haskell.org" target="_blank">Libraries@haskell.org</a><br>
>> >> <a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries</a><br>
>> ><br>
>> ><br>
><br>
><br>
</div></div></blockquote></div><br></div>
</div></div><br>_______________________________________________<br>
Libraries mailing list<br>
<a href="mailto:Libraries@haskell.org">Libraries@haskell.org</a><br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries</a><br>
<br></blockquote></div><br></div>