Proposal: Remove the bogus MonadFail instance for ST

Michael Snoyman michael at snoyman.com
Thu Mar 15 08:24:53 UTC 2018


FWIW, `fail = error` does create a law-abiding `MonadFail` for the strict
identity monad:

    Identity x >>= f = f $! x

So the generalize argument wouldn't apply to only ST, but to a much larger
class of monads.

On Thu, Mar 15, 2018 at 10:15 AM, Edward Kmett <ekmett at gmail.com> wrote:

> In particular this is distinct from an attempt like
>
> instance MonadFail Identity where
>   fail = error
>
> which already fails the left zero law as
>
> fail s >>= f = f (error e)
>
> but that right hand side is /= fail s for non-strict f.
>
> -Edward
>
> On Mar 15, 2018, at 9: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/cb6d8589c83247ec96d5faa8
>>> 2df3e93f419bbfe0:/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
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/libraries/attachments/20180315/495d3a7a/attachment.html>


More information about the Libraries mailing list