MonadFail proposal (MFP): Moving fail out of Monad

Tikhon Jelvis tikhon at jelv.is
Wed Jun 10 20:30:46 UTC 2015


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!)

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.

On Wed, Jun 10, 2015 at 12:48 PM, Edward Kmett <ekmett at gmail.com> 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.
>
> 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
>
> On Wed, Jun 10, 2015 at 6:07 PM, David Feuer <david.feuer at gmail.com>
> wrote:
>
>> But why does a string actually make sense in the context of handling
>> pattern match failures? Sticking to a Haskell 98 solution, I would
>> think MonadZero would be the way to go for those, rather than
>> MonadFail. What, after all, can you really do with the string
>> generated by a pattern match failure? For everything other than
>> pattern match failures, I would think the user should use MonadError,
>> a non-fundep MonadError, or just work directly without classes.
>>
>> On Wed, Jun 10, 2015 at 11:53 AM, Edward Kmett <ekmett at gmail.com> wrote:
>> > You could handle that case explicitly by giving a class that converted a
>> > string into e and putting that constraint on the MonadFail instance for
>> > Either:
>> >
>> > class Error a where
>> >   strMsg :: String -> a
>> >
>> > instance Error e => MonadFail (Either e) where
>> >   fail = Left . strMsg
>> >
>> > We used to do this in the mtl, with the Error class, but it then had to
>> > encumber the entire Monad, so even folks who didn't want it needed to
>> supply
>> > a garbage instance.
>> >
>> > Right now, fail for Either is necessarily _error_ because we can't put
>> it in
>> > the left side without incurring a constraint on every user of the monad.
>> >
>> > At least here the ad hoc construction can be offloaded to the particular
>> > MonadFail instance, or to whatever monad someone makes up for working
>> with
>> > their Either-like construction.
>> >
>> > -Edward
>> >
>> > On Wed, Jun 10, 2015 at 5:44 PM, David Feuer <david.feuer at gmail.com>
>> wrote:
>> >>
>> >> My main concern, I suppose, is that I don't see a way (without
>> >> extensions) to deal with even the most basic interesting failure
>> >> monad: Either e. It therefore seems really only to be suitable for
>> >> pattern match failure and user-generated IOErrors, which don't really
>> >> strike me as terribly natural bedfellows.
>> >>
>> >> On Wed, Jun 10, 2015 at 10:55 AM, Edward Kmett <ekmett at gmail.com>
>> wrote:
>> >> > This would require you to add MPTCs to the language standard, which
>> >> > means
>> >> > standardizing how they work.
>> >> >
>> >> > Any solution involving SomeException or any of its variants is going
>> to
>> >> > drag
>> >> > in GADTs, Typeable, higher rank types.
>> >> >
>> >> > ... and it would drag them inexorably into the Prelude, not just
>> base.
>> >> >
>> >> > Compared to a simple
>> >> >
>> >> > class Monad m => MonadFail m where
>> >> >   fail :: String -> m a
>> >> >
>> >> > that is a very hard sell!
>> >> >
>> >> > On the other hand, I do think what we could do is add more
>> information
>> >> > about
>> >> > pattern match failures by adding another member to the class
>> >> >
>> >> > class Monad m => MonadFail m where
>> >> >   patternMatchFailure :: Location -> String -> whatever else you
>> like ->
>> >> > m a
>> >> >   patternMatchFailure l s ... = fail (code to generate the string we
>> >> > generate in the compiler using just the parts we're passed)
>> >> >
>> >> >   fail :: String -> m a
>> >> >
>> >> > Then the existing 'fail' desugaring could be done in terms of this
>> >> > additional member and its default implementation.
>> >> >
>> >> > This remains entirely in the "small" subset of Haskell that is well
>> >> > behaved.
>> >> > It doesn't change if we go and radically redefine the way the
>> exception
>> >> > hierarchy works, and it doesn't require a ton of standardization
>> effort.
>> >> >
>> >> > Now if we want to make the fail instance for IO or other MonadThrow
>> >> > instances package up the patternMatchFailure and throw it in an
>> >> > exception we
>> >> > have the freedom, but we're avoid locking ourselves in to actually
>> >> > trying to
>> >> > figure out how to standardize all of the particulars of the exception
>> >> > machinery into the language standard.
>> >> >
>> >> > -Edward
>> >> >
>> >> > On Wed, Jun 10, 2015 at 4:19 PM, David Feuer <david.feuer at gmail.com>
>> >> > wrote:
>> >> >>
>> >> >> Here's a crazy question: would a version of MonadError without the
>> >> >> fundep do the trick?
>> >> >>
>> >> >> class Monad m => MonadFail e m where
>> >> >>   fail :: e -> m a
>> >> >>
>> >> >> instance MonadFail a [] where
>> >> >>   fail = const []
>> >> >>
>> >> >> instance (a ~ e) => MonadFail e (Either a) where
>> >> >>   fail = Left
>> >> >>
>> >> >> instance MonadFail SomeException IO where
>> >> >>   fail = throwIO
>> >> >> instance MonadFail IOException IO where
>> >> >>   fail = throwIO
>> >> >> ...
>> >> >> instance MonadFail String IO where
>> >> >>   fail = throwIO . userError
>> >> >>
>> >> >> On Wed, Jun 10, 2015 at 8:32 AM, Mario Blažević <
>> blamario at ciktel.net>
>> >> >> wrote:
>> >> >> > +1 from me.
>> >> >> >
>> >> >> >     A minor nitpick: the proposal should clarify which of the
>> >> >> > existing
>> >> >> > instances of Monad from base get a MonadFail instance. My
>> >> >> > understanding
>> >> >> > is
>> >> >> > that none of them would define fail = error, but that has not been
>> >> >> > made
>> >> >> > explicit.
>> >> >> >
>> >> >> >
>> >> >> > _______________________________________________
>> >> >> > Libraries mailing list
>> >> >> > Libraries at haskell.org
>> >> >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
>> >> >> _______________________________________________
>> >> >> Libraries mailing list
>> >> >> Libraries at haskell.org
>> >> >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
>> >> >
>> >> >
>> >
>> >
>>
>
>
> _______________________________________________
> Libraries mailing list
> Libraries at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/libraries/attachments/20150610/52e12024/attachment-0001.html>


More information about the Libraries mailing list