Proposal: Remove the bogus MonadFail instance for ST

Edward Kmett ekmett at gmail.com
Thu Mar 15 16:53:40 UTC 2018


As one data point re: your lens, STM offers a meaningful retry.

-Edward

On Thu, Mar 15, 2018 at 3:46 PM, Carter Schonwald <
carter.schonwald at gmail.com> wrote:

> So this boils down to two concerns
>
> 1) should st support refutable pattern matches , and this in turn touches
> on pure exceptions and totality concerns
>
> 2) is monad fail actually the monad zero or just support for refutable
> patterns , which may sometimes use monad zero for implementation?
>
> I’m not sure one way or another.
>
> One lens for this is: how do the arguments for monad fail differ between
> ST and STM?
>
>
> On Thu, Mar 15, 2018 at 8:22 AM Michael Snoyman <michael at snoyman.com>
> wrote:
>
>> I also find your `Point` data type telling, but I think for the opposite
>> reason. I think most people would want to avoid letting a pattern match
>> silently turn into a bottom value in the `Point` data type.
>>
>> IMO, what all of this comes down to is the fact that `MonadFail` is being
>> used in this thread for two purposes:
>>
>> 1. By you to be the general purpose zero class
>> 2. By (I think) everyone else to be the class that allows you to do
>> refutable pattern matches
>>
>> Personally, I think `fail :: String -> m a` is a bad type for a general
>> purpose zero class; either MonadZero, or a type class using `Exception`
>> like `MonadThrow` in `exceptions, would be better. And regardless, I don't
>> think we should be encouraging further usage of bottom values, even if the
>> usage of a bottom is in fact law abiding.
>>
>> On Thu, Mar 15, 2018 at 10:34 AM, Edward Kmett <ekmett at gmail.com> wrote:
>>
>>>
>>>
>>> On Mar 15, 2018, at 9:13 AM, Michael Snoyman <michael at snoyman.com>
>>> wrote:
>>>
>>> If the concern is a lack of ability to have the properly sequenced
>>> exception throwing, I would argue that the correct response is to provide a
>>> monomorphic `failST :: String -> ST s a` function to be explicit about the
>>> purpose. I'd personally go farther and make the function `throwST ::
>>> Exception e => e -> ST s a`.
>>>
>>>
>>> I definitely agree here.
>>>
>>> While it's true that `MonadFail (ST s)` obeys the laws, the point here
>>> is about the extra functionality provided by `MonadFail`, namely around
>>> pattern matching. I think the question can be boiled down to: do we want to
>>> make it easy to call `fail` when writing code inside `ST`?
>>>
>>>
>>> My point was more that this is rather distinct from the other cases
>>> mentioned in that it is a true legal instance, enabling things like a
>>> fail-based guard to actually protect against subsequent code in ST
>>> executing.
>>>
>>> I do find it telling that we can get into a similar situation completely
>>> without effects with
>>>
>>> data Point a = Point a
>>>
>>> ...
>>>
>>> instance Monad Point where
>>>   return = Point
>>>   Point a >>= f = f a
>>>
>>> instance MonadFail Point where
>>>   fail = error
>>>
>>> the extra "point" added by using data rather than newtype and the strict
>>> pattern match in >>= plumbs the error out in the same fashion as ST here.
>>>
>>> I find the ability to explicitly construct bottoms at the right time to
>>> guard subsequent operations in those monads to be a piece of vocabulary
>>> that would be otherwise missing if we retroactively tried to impose some
>>> additional handling laws that aren't required by having a cancellative zero.
>>>
>>> On Thu, Mar 15, 2018 at 10:00 AM, Edward Kmett <ekmett at gmail.com> wrote:
>>>
>>>> I'm a bit less convinced about the benefits removing the instance for
>>>> MonadFail (ST s).
>>>>
>>>> Playing devil's advocate here:
>>>>
>>>> Recall that throwIO is distinct from throw for a good reason, as it
>>>> ensures that the throwing occurs at the right step in the sequence of binds.
>>>>
>>>> The `fail` instance for ST can similarly be viewed as a perfectly
>>>> reasonable monotone function affecting the result of runST :: (forall s. ST
>>>> s a) -> a, which produces an `a` that is the appropriate bottom at the
>>>> right time when you take a certain branch in the ST calculation. This is
>>>> rather different than Identity, as you can't just ape this behavior by
>>>> calling 'error' instead as you need the smarter call.
>>>>
>>>> To achieve that functionality today _without_ fail, you need to reach
>>>> for unsafe operations `unsafeIOtoST . failIO` it to get the correct
>>>> semantics, which is a damn sight messier and scarier and importantly
>>>> removing the instance means this can't be something that is done by just
>>>> delegating to base monad transformer 'fail' as would be done through
>>>> something like `StateT s (ST s')`. This seems to create a false tension
>>>> between doing the most defined thing and doing the thing I want with a
>>>> stronger constraint, which I usually take as a sign that the building
>>>> blocks are wrong.
>>>>
>>>> Removing this instance comes at a real cost in terms of generality of
>>>> code that uses `MonadFail`:  It does pass the left zero law!
>>>>
>>>> Overall, I'm -1, as I'm actually leaning against the removal of the
>>>> instance personally on the grounds above.
>>>>
>>>> -Edward
>>>>
>>>> On Wed, Mar 14, 2018 at 3:31 PM, Michael Snoyman <michael at snoyman.com>
>>>> wrote:
>>>>
>>>>> One possible "well behaved" intuition could be "cannot result in an
>>>>> exception thrown from pure code without usage of unsafe functions." By this
>>>>> definition:
>>>>>
>>>>> * Maybe's fail is well behaved: using `fail "foo"` results in a total
>>>>> Nothing value
>>>>> * List's: same thing, but with an empty list
>>>>> * IO: runtime exception, but the exception is _not_ in pure code, but
>>>>> rather from within IO, where exceptions are always to be expected
>>>>> * ST: `runST (fail "foo")` results in a pure value which, when
>>>>> evaluated, throws a runtime exception, breaking the well behaved definition
>>>>> * Identity: `Identity (fail "foo")` can only be a pure value which
>>>>> throws an exception, and is therefore not well behaved
>>>>>
>>>>> Note that I added the requirement of "without usage of unsafe
>>>>> functions," since `unsafePerformIO (fail "foo")` can result in a pure
>>>>> bottom value.
>>>>>
>>>>> On Wed, Mar 14, 2018 at 4:25 PM, Ryan Scott <ryan.gl.scott at gmail.com>
>>>>> wrote:
>>>>>
>>>>>> Thanks, that makes more sense. I'm inclined to agree that MonadFail
>>>>>> instances should fail in a "well-behaved" way. (I wish I knew how to
>>>>>> make the phrase "well-behaved" more formal, but I don't.) It might be
>>>>>> worth adding this intuition to the Haddocks for MonadFail.
>>>>>>
>>>>>> That being said, one thing to consider before removing this instance
>>>>>> is that there will be some breakage. Ben Gamari added this instance in
>>>>>> [1] because apparently the regex-tdfa package needed it. Other than
>>>>>> that, though, I don't have any real objections to removing this
>>>>>> instance.
>>>>>>
>>>>>> Ryan S.
>>>>>> -----
>>>>>> [1] https://phabricator.haskell.org/D3982
>>>>>>
>>>>>> On Wed, Mar 14, 2018 at 9:58 AM, David Feuer <david.feuer at gmail.com>
>>>>>> wrote:
>>>>>> > I expect a MonadFail instance to have a well-behaved notion of
>>>>>> failure
>>>>>> > within the monad. An exception from "pure" code (which is what ST
>>>>>> > simulates) is not that. On the other hand, perhaps you're right and
>>>>>> > the instance should be removed for IO as well; I don't have as
>>>>>> strong
>>>>>> > a sense of revulsion, but maybe users should be forced to be
>>>>>> explicit
>>>>>> > with throwIO.
>>>>>> >
>>>>>> > On Wed, Mar 14, 2018 at 9:46 AM, Ryan Scott <
>>>>>> ryan.gl.scott at gmail.com> wrote:
>>>>>> >> OK. You used the phrase "utterly contrary to the purpose of
>>>>>> >> MonadFail", so I'm trying to figure out exactly what you mean here.
>>>>>> >> Prima facie, the purpose of MonadFail (at least, as explained in
>>>>>> its
>>>>>> >> Haddocks) is to provide a type class–directed way of desugaring
>>>>>> >> partial pattern matches in do-notation. With this in mind, the
>>>>>> current
>>>>>> >> MonadFail instance for ST doesn't seem too offensive.
>>>>>> >>
>>>>>> >> However, I think you have some additional property in mind that you
>>>>>> >> feel the MonadFail ST instance runs afoul of. Do you mind
>>>>>> explaining
>>>>>> >> in further detail what this is? (I'm not trying to be snarky here—I
>>>>>> >> genuinely don't know what you're getting at.)
>>>>>> >>
>>>>>> >> Ryan S.
>>>>>> >>
>>>>>> >> On Wed, Mar 14, 2018 at 9:41 AM, David Feuer <
>>>>>> david.feuer at gmail.com> wrote:
>>>>>> >>> I am not. I think that instance is fairly legitimate, as it
>>>>>> raises an
>>>>>> >>> IO exception that can be caught in IO. IO's Alternative instance
>>>>>> is a
>>>>>> >>> bit shadier, but that's not a topic for this proposal either. ST
>>>>>> is an
>>>>>> >>> entirely different story, and I'm sorry I accidentally mixed it
>>>>>> in.
>>>>>> >>>
>>>>>> >>> On Wed, Mar 14, 2018 at 9:05 AM, Ryan Scott <
>>>>>> ryan.gl.scott at gmail.com> wrote:
>>>>>> >>>> It's worth noting that the MonadFail instance for IO [1] also
>>>>>> simply throws
>>>>>> >>>> an error (by way of failIO). Are you proposing we remove this
>>>>>> instance as
>>>>>> >>>> well?
>>>>>> >>>>
>>>>>> >>>> Ryan S.
>>>>>> >>>> -----
>>>>>> >>>> [1]
>>>>>> >>>> http://git.haskell.org/ghc.git/blob/
>>>>>> cb6d8589c83247ec96d5faa82df3e93f419bbfe0:/libraries/base/
>>>>>> Control/Monad/Fail.hs#l80
>>>>>> >>>>
>>>>>> >>>> _______________________________________________
>>>>>> >>>> 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
>>>>>
>>>>>
>>>>
>>>
>> _______________________________________________
>> 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/20180315/4d94045a/attachment-0001.html>


More information about the Libraries mailing list