MonadFail proposal (MFP): Moving fail out of Monad

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hello *, the subject says it all. After we successfully put `=>` into Monad, it is time to remove something in return: `fail`. Like with the AMP, I wrote up the proposal in Markdown format on Github, which you can find below as a URL, and in verbatim copy at the end of this email. It provides an overview over the intended outcome, which design decisions we had to take, and how our initial plan for the transition looks like. There are also some issues left open to discussion. https://github.com/quchen/articles/blob/master/monad_fail.md Here's a short abstract: - - Move `fail` from `Monad` into a new class `MonadFail`. - - Code using failable patterns will receive a more restrictive `MonadFail` constraint. Code without this constraint will be safe to use for all Monads. - - Transition will take at least two GHC releases. GHC 7.12 will include the new class, and generate warnings asking users to make their failable patterns compliant. - - Stackage showed an upper bound of less than 500 breaking code fragments when compiled with the new desugaring. For more details, refer to the link or the paste at the end. Let's get going! David aka quchen =============================================================== =============================================================== =============================================================== `MonadFail` proposal (MFP) ========================== A couple of years ago, we proposed to make `Applicative` a superclass of `Monad`, which successfully killed the single most ugly thing in Haskell as of GHC 7.10. Now, it's time to tackle the other major issue with `Monad`: `fail` being a part of it. You can contact me as usual via IRC/Freenode as *quchen*, or by email to *dluposchainsky at the email service of Google*. This file will also be posted on the ghc-devs@ and libraries@ mailing lists, as well as on Reddit. Overview - -------- - - **The problem** - reason for the proposal - - **MonadFail class** - the solution - - **Discussion** - explaining our design choices - - **Adapting old code** - how to prepare current code to transition smoothly - - **Esimating the breakage** - how much stuff we will break (spoiler: not much) - - **Transitional strategy** - how to break as little as possible while transitioning - - **Current status** The problem - ----------- Currently, the `<-` symbol is unconditionally desugared as follows: ```haskell do pat <- computation >>> let f pat = more more >>> f _ = fail "..." >>> in computation >>= f ``` The problem with this is that `fail` cannot (!) be sensibly implemented for many monads, for example `State`, `IO`, `Reader`. In those cases it defaults to `error`. As a consequence, in current Haskell, you can not use `Monad`-polymorphic code safely, because although it claims to work for all `Monad`s, it might just crash on you. This kind of implicit non-totality baked into the class is *terrible*. The goal of this proposal is adding the `fail` only when necessary and reflecting that in the type signature of the `do` block, so that it can be used safely, and more importantly, is guaranteed not to be used if the type signature does not say so. `MonadFail` class - ----------------- To fix this, introduce a new typeclass: ```haskell class Monad m => MonadFail m where fail :: String -> m a ``` Desugaring can now be changed to produce this constraint when necessary. For this, we have to decide when a pattern match can not fail; if this is the case, we can omit inserting the `fail` call. The most trivial examples of unfailable patterns are of course those that match anywhere unconditionally, ```haskell do x <- action >>> let f x = more more >>> in action >>= f ``` In particular, the programmer can assert any pattern be unfailable by making it irrefutable using a prefix tilde: ```haskell do ~pat <- action >>> let f ~pat = more more >>> in action >>= f ``` A class of patterns that are conditionally failable are `newtype`s, and single constructor `data` types, which are unfailable by themselves, but may fail if matching on their fields is done with failable paterns. ```haskell data Newtype a = Newtype a - -- "x" cannot fail do Newtype x <- action >>> let f (Newtype x) = more more >>> in action >>= f - -- "Just x" can fail do Newtype (Just x) <- action >>> let f (Newtype (Just x)) = more more >>> f _ = fail "..." >>> in action >>= f ``` `ViewPatterns` are as failable as the pattern the view is matched against. Patterns like `(Just -> Just x)` should generate a `MonadFail` constraint even when it's "obvious" from the view's implementation that the pattern will always match. From an implementor's perspective, this means that only types (and their constructors) have to be looked at, not arbitrary values (like functions), which is impossible to do statically in general. ```haskell do (view -> pat) <- action >>> let f (view -> pat) = more more >>> f _ = fail "..." >>> in action >>= f do (view -> ~pat) <- action >>> let f (view -> ~pat) = more more >>> in action >>= f ``` A similar issue arises for `PatternSynonyms`, which we cannot inspect during compilation sufficiently. A pattern synonym will therefore always be considered failable. ```haskell do PatternSynonym x <- action >>> let f PatternSynonym x = more more >>> in f _ = fail "..." >>> in action >>= f ``` Discussion - ---------- - - Although for many `MonadPlus` `fail _ = mzero`, a separate `MonadFail` class should be created instead of just using that. - A parser might fail with an error message involving positional information. Some libraries, like `Binary`, provide `fail` as their only interface to fail a decoding step. - Although `STM` is `MonadPlus`, it uses the default `fail = error`. It will therefore not get a `MonadFail` instance. - - What laws should `fail` follow? **Left zero**, ```haskell ∀ s f. fail s >>= f ≡ fail s ``` A call to `fail` should abort the computation. In this sense, `fail` would become a close relative of `mzero`. It would work well with the common definition `fail _ = mzero`, and give a simple guideline to the intended usage and effect of the `MonadFail` class. - - Rename `fail`? **No.** Old code might use `fail` explicitly and we might avoid breaking it, the Report talks about `fail`, and we have a solid migration strategy that does not require a renaming. - - Remove the `String` argument? **No.** The `String` might help error reporting and debugging. `String` may be ugly, but it's the de facto standard for simple text in GHC. No high performance string operations are to be expected with `fail`, so this breaking change would in no way be justified. Also note that explicit `fail` calls would break if we removed the argument. - - How sensitive would existing code be to subtle changes in the strictness behaviour of `do` notation pattern matching? **It doesn't.** The implementation does not affect strictness at all, only the desugaring step. Care must be taken when fixing warnings by making patterns irrefutable using `~`, as that *does* affect strictness. (Cf. difference between lazy/strict State) - - The `Monad` constraint for `MonadFail` seems unnecessary. Should we drop or relax it? What other things should be considered? - Applicative `do` notation is coming sooner or later, `fail` might be useful in this more general scenario. Due to the AMP, it is trivial to change the `MonadFail` superclass to `Applicative` later. (The name will be a bit misleading, but it's a very small price to pay.) - The class might be misused for a strange pointed type if left without any constraint. This is not the intended use at all. I think we should keep the `Monad` superclass for three main reasons: - We don't want to see `(Monad m, MonadFail m) =>` all over the place. - The primary intended use of `fail` is for desugaring do-notation anyway. - Retroactively removing superclasses is easy, but adding them is hard (see AMP). Adapting old code - ----------------- - - Help! My code is broken because of a missing `MonadFail` instance! *Here are your options:* 1. Write a `MonadFail` instance (and bring it into scope) ```haskell #if !MIN_VERSION_base(4,11,0) -- Control.Monad.Fail import will become redundant in GHC 7.16+ import qualified Control.Monad.Fail as Fail #endif import Control.Monad instance Monad Foo where (>>=) = <...bind impl...> -- NB: `return` defaults to `pure` #if !MIN_VERSION_base(4,11,0) -- Monad(fail) will be removed in GHC 7.16+ fail = Fail.fail #endif instance MonadFail Foo where fail = <...fail implementation...> ``` 2. Change your pattern to be irrefutable 3. Emulate the old behaviour by desugaring the pattern match by hand: ```haskell do Left e <- foobar stuff ``` becomes ```haskell do x <- foobar e <- case foobar of Left e' -> e' Right r -> error "Pattern match failed" -- Boooo stuff ``` The point is you'll have to do your dirty laundry yourself now if you have a value that *you* know will always match, and if you don't handle the other patterns you'll get incompleteness warnings, and the compiler won't silently eat those for you. - - Help! My code is broken because you removed `fail` from `Monad`, but my class defines it! *Delete that part of the instance definition.* Esimating the breakage - ---------------------- Using our initial implementation, I compiled stackage-nightly, and grepped the logs for found "invalid use of fail desugaring". Assuming my implementation is correct, the number of "missing `MonadFail`" warnings generated is 487. Note that I filtered out `[]`, `Maybe` and `ReadPrec`, since those can be given a `MonadFail` instance from within GHC, and no breakage is expected from them. The build logs can be found [here][stackage-logs]. Search for "failable pattern" to find your way to the still pretty raw warnings. Transitional strategy - --------------------- The roadmap is similar to the [AMP][amp], the main difference being that since `MonadFail` does not exist yet, we have to introduce new functionality and then switch to it. * **GHC 7.12 / base-4.9** - Add module `Control.Monad.Fail` with new class `MonadFail(fail)` so people can start writing instances for it. `Control.Monad` only re-exports the class `MonadFail`, but not its `fail` method. NB: At this point, `Control.Monad.Fail.fail` clashes with `Prelude.fail` and `Control.Monad.fail`. - *(non-essential)* Add a language extension `-XMonadFail` that changes desugaring to use `MonadFail(fail)` instead of `Monad(fail)`. This has the effect that typechecking will infer a `MonadFail` constraint for `do` blocks with failable patterns, just as it is planned to do when the entire thing is done. - Warn when a `do`-block that contains a failable pattern is desugared, but there is no `MonadFail`-instance in scope: "Please add the instance or change your pattern matching." Add a flag to control whether this warning appears. - Warn when an instance implements the `fail` function (or when `fail` is imported as a method of `Monad`), as it will be removed from the `Monad` class in the future. (See also [GHC #10071][trac-10071]) 3. GHC 7.14 - Switch `-XMonadFail` on by default. - Remove the desugaring warnings. 3. GHC 7.16 - Remove `-XMonadFail`, leaving its effects on at all times. - Remove `fail` from `Monad`. - Instead, re-export `Control.Monad.Fail.fail` as `Prelude.fail` and `Control.Monad.fail`. - `Control.Monad.Fail` is now a redundant module that can be considered deprecated. Current status - -------------- - - [ZuriHac 2015 (29.5. - 31.5.)][zurihac]: Franz Thoma (@fmthoma) and me (David Luposchainsky aka @quchen) started implementing the MFP in GHC. - Desugaring to the new `fail` can be controlled via a new langauge extension, `MonadFailDesugaring`. - If the language extension is turned off, a warning will be emitted for code that would break if it was enabled. - Warnings are emitted for types that *have* a *MonadFail* instance. This still needs to be fixed. - The error message are readable, but should be more so. We're still on this. - - 2015-06-09: Estimated breakage by compiling Stackage. Smaller than expected. [amp]: https://github.com/quchen/articles/blob/master/applicative_monad.md [stackage-logs]: https://www.dropbox.com/s/knz0i979skam4zs/stackage-build.tar.xz?dl=0 [trac-10071]: https://ghc.haskell.org/trac/ghc/ticket/10071 [zurihac]: https://wiki.haskell.org/ZuriHac2015 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAEBAgAGBQJVd0/yAAoJELrQsaT5WQUshbUH/A3W0itVAk7ao8rtxId5unCJ 7StriKVkTyLAkkrbRJngM4MHEKiCsoyIgr8kBIwSHgk194GxeP2NCF4ijuBZoDBt +Uci+6BCBinV8+OzfrfTcJb4+8iw1j+eLWJ/Nz/JDMDNCiyzyC0SMsqGa+ssOz7H /2mqPkQjQgpHuP5PTRLHKPPIsayCQvTbZR1f14KhuMN2SPDE+WY4rqugu//XuIkN u1YssIf5l8mEez/1ljaqGL55cTI0UNg2z0iA0bFl/ajHaeQ6mc5BAevWfSohAMW7 7PIt13p9NIaMHnikmI+YJszm2IEaXuv47mGgbyDV//nHq3fwWN+naB+1mPX2eSU= =vPAL -----END PGP SIGNATURE-----

On Tue, 9 Jun 2015, David Luposchainsky wrote:
the subject says it all. After we successfully put `=>` into Monad, it is time to remove something in return: `fail`.
Let me start the "+1" flood with my own +1.
- - Stackage showed an upper bound of less than 500 breaking code fragments when compiled with the new desugaring.
I found that code breakage generally is not a big problem for me. I can fix code and that's it. I am more concerned with writing code that can be compiled by several GHC versions.

Definitely +1 here, but if you have an irrefutable pattern:
~(Just x) <- action
... expresison involving x ...
My understanding is that 'fail' is only called if you evaluate 'x'.
So I guess any expression with 'x' in it would also imply the
MonadFail constraint. So ~ might just move the constraint until the
next line. Or if you pass 'x' to someone else, do they now get
MonadFail?
Would it be worth pointing that out?
On Tue, Jun 9, 2015 at 1:43 PM, David Luposchainsky
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Hello *,
the subject says it all. After we successfully put `=>` into Monad, it is time to remove something in return: `fail`.
Like with the AMP, I wrote up the proposal in Markdown format on Github, which you can find below as a URL, and in verbatim copy at the end of this email. It provides an overview over the intended outcome, which design decisions we had to take, and how our initial plan for the transition looks like. There are also some issues left open to discussion.
https://github.com/quchen/articles/blob/master/monad_fail.md
Here's a short abstract:
- - Move `fail` from `Monad` into a new class `MonadFail`. - - Code using failable patterns will receive a more restrictive `MonadFail` constraint. Code without this constraint will be safe to use for all Monads. - - Transition will take at least two GHC releases. GHC 7.12 will include the new class, and generate warnings asking users to make their failable patterns compliant. - - Stackage showed an upper bound of less than 500 breaking code fragments when compiled with the new desugaring.
For more details, refer to the link or the paste at the end.
Let's get going!
David aka quchen
=============================================================== =============================================================== ===============================================================
`MonadFail` proposal (MFP) ==========================
A couple of years ago, we proposed to make `Applicative` a superclass of `Monad`, which successfully killed the single most ugly thing in Haskell as of GHC 7.10.
Now, it's time to tackle the other major issue with `Monad`: `fail` being a part of it.
You can contact me as usual via IRC/Freenode as *quchen*, or by email to *dluposchainsky at the email service of Google*. This file will also be posted on the ghc-devs@ and libraries@ mailing lists, as well as on Reddit.
Overview - --------
- - **The problem** - reason for the proposal - - **MonadFail class** - the solution - - **Discussion** - explaining our design choices - - **Adapting old code** - how to prepare current code to transition smoothly - - **Esimating the breakage** - how much stuff we will break (spoiler: not much) - - **Transitional strategy** - how to break as little as possible while transitioning - - **Current status**
The problem - -----------
Currently, the `<-` symbol is unconditionally desugared as follows:
```haskell do pat <- computation >>> let f pat = more more >>> f _ = fail "..." >>> in computation >>= f ```
The problem with this is that `fail` cannot (!) be sensibly implemented for many monads, for example `State`, `IO`, `Reader`. In those cases it defaults to `error`. As a consequence, in current Haskell, you can not use `Monad`-polymorphic code safely, because although it claims to work for all `Monad`s, it might just crash on you. This kind of implicit non-totality baked into the class is *terrible*.
The goal of this proposal is adding the `fail` only when necessary and reflecting that in the type signature of the `do` block, so that it can be used safely, and more importantly, is guaranteed not to be used if the type signature does not say so.
`MonadFail` class - -----------------
To fix this, introduce a new typeclass:
```haskell class Monad m => MonadFail m where fail :: String -> m a ```
Desugaring can now be changed to produce this constraint when necessary. For this, we have to decide when a pattern match can not fail; if this is the case, we can omit inserting the `fail` call.
The most trivial examples of unfailable patterns are of course those that match anywhere unconditionally,
```haskell do x <- action >>> let f x = more more >>> in action >>= f ```
In particular, the programmer can assert any pattern be unfailable by making it irrefutable using a prefix tilde:
```haskell do ~pat <- action >>> let f ~pat = more more >>> in action >>= f ```
A class of patterns that are conditionally failable are `newtype`s, and single constructor `data` types, which are unfailable by themselves, but may fail if matching on their fields is done with failable paterns.
```haskell data Newtype a = Newtype a
- -- "x" cannot fail do Newtype x <- action >>> let f (Newtype x) = more more >>> in action >>= f
- -- "Just x" can fail do Newtype (Just x) <- action >>> let f (Newtype (Just x)) = more more >>> f _ = fail "..." >>> in action >>= f ```
`ViewPatterns` are as failable as the pattern the view is matched against. Patterns like `(Just -> Just x)` should generate a `MonadFail` constraint even when it's "obvious" from the view's implementation that the pattern will always match. From an implementor's perspective, this means that only types (and their constructors) have to be looked at, not arbitrary values (like functions), which is impossible to do statically in general.
```haskell do (view -> pat) <- action >>> let f (view -> pat) = more more >>> f _ = fail "..." >>> in action >>= f
do (view -> ~pat) <- action >>> let f (view -> ~pat) = more more >>> in action >>= f ```
A similar issue arises for `PatternSynonyms`, which we cannot inspect during compilation sufficiently. A pattern synonym will therefore always be considered failable.
```haskell do PatternSynonym x <- action >>> let f PatternSynonym x = more more >>> in f _ = fail "..." >>> in action >>= f ```
Discussion - ----------
- - Although for many `MonadPlus` `fail _ = mzero`, a separate `MonadFail` class should be created instead of just using that.
- A parser might fail with an error message involving positional information. Some libraries, like `Binary`, provide `fail` as their only interface to fail a decoding step.
- Although `STM` is `MonadPlus`, it uses the default `fail = error`. It will therefore not get a `MonadFail` instance.
- - What laws should `fail` follow? **Left zero**,
```haskell ∀ s f. fail s >>= f ≡ fail s ```
A call to `fail` should abort the computation. In this sense, `fail` would become a close relative of `mzero`. It would work well with the common definition `fail _ = mzero`, and give a simple guideline to the intended usage and effect of the `MonadFail` class.
- - Rename `fail`? **No.** Old code might use `fail` explicitly and we might avoid breaking it, the Report talks about `fail`, and we have a solid migration strategy that does not require a renaming.
- - Remove the `String` argument? **No.** The `String` might help error reporting and debugging. `String` may be ugly, but it's the de facto standard for simple text in GHC. No high performance string operations are to be expected with `fail`, so this breaking change would in no way be justified. Also note that explicit `fail` calls would break if we removed the argument.
- - How sensitive would existing code be to subtle changes in the strictness behaviour of `do` notation pattern matching? **It doesn't.** The implementation does not affect strictness at all, only the desugaring step. Care must be taken when fixing warnings by making patterns irrefutable using `~`, as that *does* affect strictness. (Cf. difference between lazy/strict State)
- - The `Monad` constraint for `MonadFail` seems unnecessary. Should we drop or relax it? What other things should be considered?
- Applicative `do` notation is coming sooner or later, `fail` might be useful in this more general scenario. Due to the AMP, it is trivial to change the `MonadFail` superclass to `Applicative` later. (The name will be a bit misleading, but it's a very small price to pay.) - The class might be misused for a strange pointed type if left without any constraint. This is not the intended use at all.
I think we should keep the `Monad` superclass for three main reasons:
- We don't want to see `(Monad m, MonadFail m) =>` all over the place. - The primary intended use of `fail` is for desugaring do-notation anyway. - Retroactively removing superclasses is easy, but adding them is hard (see AMP).
Adapting old code - -----------------
- - Help! My code is broken because of a missing `MonadFail` instance!
*Here are your options:*
1. Write a `MonadFail` instance (and bring it into scope)
```haskell #if !MIN_VERSION_base(4,11,0) -- Control.Monad.Fail import will become redundant in GHC 7.16+ import qualified Control.Monad.Fail as Fail #endif import Control.Monad
instance Monad Foo where (>>=) = <...bind impl...> -- NB: `return` defaults to `pure`
#if !MIN_VERSION_base(4,11,0) -- Monad(fail) will be removed in GHC 7.16+ fail = Fail.fail #endif
instance MonadFail Foo where fail = <...fail implementation...> ```
2. Change your pattern to be irrefutable
3. Emulate the old behaviour by desugaring the pattern match by hand:
```haskell do Left e <- foobar stuff ```
becomes
```haskell do x <- foobar e <- case foobar of Left e' -> e' Right r -> error "Pattern match failed" -- Boooo stuff ```
The point is you'll have to do your dirty laundry yourself now if you have a value that *you* know will always match, and if you don't handle the other patterns you'll get incompleteness warnings, and the compiler won't silently eat those for you.
- - Help! My code is broken because you removed `fail` from `Monad`, but my class defines it!
*Delete that part of the instance definition.*
Esimating the breakage - ----------------------
Using our initial implementation, I compiled stackage-nightly, and grepped the logs for found "invalid use of fail desugaring". Assuming my implementation is correct, the number of "missing `MonadFail`" warnings generated is 487. Note that I filtered out `[]`, `Maybe` and `ReadPrec`, since those can be given a `MonadFail` instance from within GHC, and no breakage is expected from them.
The build logs can be found [here][stackage-logs]. Search for "failable pattern" to find your way to the still pretty raw warnings.
Transitional strategy - ---------------------
The roadmap is similar to the [AMP][amp], the main difference being that since `MonadFail` does not exist yet, we have to introduce new functionality and then switch to it.
* **GHC 7.12 / base-4.9**
- Add module `Control.Monad.Fail` with new class `MonadFail(fail)` so people can start writing instances for it.
`Control.Monad` only re-exports the class `MonadFail`, but not its `fail` method.
NB: At this point, `Control.Monad.Fail.fail` clashes with `Prelude.fail` and `Control.Monad.fail`.
- *(non-essential)* Add a language extension `-XMonadFail` that changes desugaring to use `MonadFail(fail)` instead of `Monad(fail)`.
This has the effect that typechecking will infer a `MonadFail` constraint for `do` blocks with failable patterns, just as it is planned to do when the entire thing is done.
- Warn when a `do`-block that contains a failable pattern is desugared, but there is no `MonadFail`-instance in scope: "Please add the instance or change your pattern matching." Add a flag to control whether this warning appears.
- Warn when an instance implements the `fail` function (or when `fail` is imported as a method of `Monad`), as it will be removed from the `Monad` class in the future. (See also [GHC #10071][trac-10071])
3. GHC 7.14
- Switch `-XMonadFail` on by default. - Remove the desugaring warnings.
3. GHC 7.16
- Remove `-XMonadFail`, leaving its effects on at all times. - Remove `fail` from `Monad`. - Instead, re-export `Control.Monad.Fail.fail` as `Prelude.fail` and `Control.Monad.fail`. - `Control.Monad.Fail` is now a redundant module that can be considered deprecated.
Current status - --------------
- - [ZuriHac 2015 (29.5. - 31.5.)][zurihac]: Franz Thoma (@fmthoma) and me (David Luposchainsky aka @quchen) started implementing the MFP in GHC.
- Desugaring to the new `fail` can be controlled via a new langauge extension, `MonadFailDesugaring`. - If the language extension is turned off, a warning will be emitted for code that would break if it was enabled. - Warnings are emitted for types that *have* a *MonadFail* instance. This still needs to be fixed. - The error message are readable, but should be more so. We're still on this. - - 2015-06-09: Estimated breakage by compiling Stackage. Smaller than expected.
[amp]: https://github.com/quchen/articles/blob/master/applicative_monad.md [stackage-logs]: https://www.dropbox.com/s/knz0i979skam4zs/stackage-build.tar.xz?dl=0 [trac-10071]: https://ghc.haskell.org/trac/ghc/ticket/10071 [zurihac]: https://wiki.haskell.org/ZuriHac2015
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1
iQEcBAEBAgAGBQJVd0/yAAoJELrQsaT5WQUshbUH/A3W0itVAk7ao8rtxId5unCJ 7StriKVkTyLAkkrbRJngM4MHEKiCsoyIgr8kBIwSHgk194GxeP2NCF4ijuBZoDBt +Uci+6BCBinV8+OzfrfTcJb4+8iw1j+eLWJ/Nz/JDMDNCiyzyC0SMsqGa+ssOz7H /2mqPkQjQgpHuP5PTRLHKPPIsayCQvTbZR1f14KhuMN2SPDE+WY4rqugu//XuIkN u1YssIf5l8mEez/1ljaqGL55cTI0UNg2z0iA0bFl/ajHaeQ6mc5BAevWfSohAMW7 7PIt13p9NIaMHnikmI+YJszm2IEaXuv47mGgbyDV//nHq3fwWN+naB+1mPX2eSU= =vPAL -----END PGP SIGNATURE----- _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

On Tue, 9 Jun 2015, Evan Laforge wrote:
Definitely +1 here, but if you have an irrefutable pattern:
~(Just x) <- action ... expresison involving x ...
My understanding is that 'fail' is only called if you evaluate 'x'.
I think you would no longer have an (overloadable) "fail", but a (hardwired) "error".

On 2015-06-09 at 22:43:30 +0200, David Luposchainsky wrote: [...]
https://github.com/quchen/articles/blob/master/monad_fail.md
Here's a short abstract:
- Move `fail` from `Monad` into a new class `MonadFail`.
[...] +1 obviously :-)

Hi, Am Dienstag, den 09.06.2015, 22:43 +0200 schrieb David Luposchainsky:
the subject says it all. After we successfully put `=>` into Monad, it is time to remove something in return: `fail`.
your proposal is solid work and very thorough. Thanks! Greetings, Joachim -- Joachim “nomeata” Breitner mail@joachim-breitner.de • http://www.joachim-breitner.de/ Jabber: nomeata@joachim-breitner.de • GPG-Key: 0xF0FBF51F Debian Developer: nomeata@debian.org

now some details to the discussion: On Tue, 9 Jun 2015, David Luposchainsky wrote:
https://github.com/quchen/articles/blob/master/monad_fail.md
Here's a short abstract:
- - Move `fail` from `Monad` into a new class `MonadFail`.
You think about making MonadFail a subclass of Applicative where the name MonadFail becomes misleading - how about naming it Fail instead?
- - Remove the `String` argument? **No.** The `String` might help error reporting and debugging. `String` may be ugly, but it's the de facto standard for simple text in GHC. No high performance string operations are to be expected with `fail`, so this breaking change would in no way be justified. Also note that explicit `fail` calls would break if we removed the argument.
You know that I am concerned with a strict separation of programming errors and exceptions. "fail" is part of the confusion between the two concepts. If "fail" is inserted by the compiler as desugaring of a pattern match then it gets a compiler generated string as argument. This string refers to program details like source locations and constructor names that have no meaning for the program user. They are intended for debugging, they address the programmer. This implies that "fail" indicates a programming error. In contrast to that, in a monad like Maybe we want to convert a mismatching pattern to Nothing. The compiler generated argument to "fail" does not show up in the Nothing result. This usecase is clearly not for debugging but for regular use in a program. We only want to get the exceptional value Nothing. We should clearly decide what "fail" is intended for - for programming errors or for exceptions. I guess that people want to use it in the second sense, e.g. something like "guard" driven by a pattern match in the Maybe or list monad. But then "fail" must not have an argument because what user related information can the compiler add automatically? Instead of removing the String argument from "fail", the compiler could simply call "mzero" instead. If we want to use "fail" for exceptions then it would be also ok for parser libraries to use it for parser failures. Nonetheless they might be better served with an Except-like monad where they can choose more specific types for the exception messages, e.g. parser errors with source location. In summary I think that the cleanest solution would be to phase out "fail" completely in the long run. But using "mzero" instead of "fail" for monadic pattern matches would alter the proposal considerably. Using "mzero" requires a monad with "mplus" and for support of monads with "mzero" but no "mplus" we need to split MonadPlus, too.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 09.06.2015 23:56, Henning Thielemann wrote:
You think about making MonadFail a subclass of Applicative where the name MonadFail becomes misleading - how about naming it Fail instead?
I discussed this with Herbert a bit already. The problem with the name "Fail" is that, if Monad being superclasses of it, hides the fact that there is such a Monad constraint. Instead, the user has to know that Fail happens to be a subclass of Monad, and the Monad part is probably the most important thing in the type, not that there might be some failable pattern somewhere. The name MonadFail solves this issue by containing "Monad" in its name, but the price we pay for that is the awkwardness if we relax the superclass.
We should clearly decide what "fail" is intended for - for programming errors or for exceptions. I guess that people want to use it in the second sense, e.g. something like "guard" driven by a pattern match in the Maybe or list monad. But then "fail" must not have an argument because what user related information can the compiler add automatically? Instead of removing the String argument from "fail", the compiler could simply call "mzero" instead.
mzero is only available in MonadPlus, which we want to be independent of MonadFail. I don't see a way to accomplish this goal without adding more complicated desugaring rules.
If we want to use "fail" for exceptions then it would be also ok for parser libraries to use it for parser failures. Nonetheless they might be better served with an Except-like monad where they can choose more specific types for the exception messages, e.g. parser errors with source location. But using "mzero" instead of "fail" for monadic pattern matches would alter the proposal considerably. Using "mzero" requires a monad with "mplus" and for support of monads with "mzero" but no "mplus" we need to split MonadPlus, too.
In summary I think that the cleanest solution would be to phase out "fail" completely in the long run.
If we desugar to anything but simply >>=, we're in a realm of mixups already. Splitting MonadPlus would be quite an effort, and I don't think it would be worth it. I agree that <- should desugar straight to >>=. I have not considered removing the fail desugaring altogether, but I have no idea how much code that would break. The build logs I posted show roughly 100 Maybe/List invocations with failable patterns, but we should also not forget about all the explicit "fail" calls that libraries might do. All things considered, I don't think we're ready for (judging) this, but maybe we can revisit the issue some day and simply deprecate MonadFail; in that sense, we're not going in the wrong direction right now at least. Greetings, David/quchen -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAEBAgAGBQJVd2bNAAoJELrQsaT5WQUsCOMH/0e73pZbXH8r98RpgB4sRU33 ZMZwmkA2wPA5nN996E+cqDmkbCm2qj+O0X3nVkdsM7qi+oRnubnlKWTe+YpPnBsP in1GGwo9eSry7z4Qyw6ZVIeRXufrjQrze+zQH+dBG/O6Qrrze+t9w9YGAWJxDMVa KcBdpd4gRXHZH6y0aXEK1eyroIF1k7XVrK4XVyI+WYu2JjpTHWLjaCBzDVS0+PXU mnTbnA0CrLpGrjCdSiIBeU4ezc57Sn3aNy5gKlZNIchTV81Q/5y5wGE6t/V9wqz4 2fTohs4GWhyjCjLnr6NXWSQDtJN8CUQOadgz9qYnyGOawrKjWQND/ybi3zWE2ZY= =1hmy -----END PGP SIGNATURE-----

On 2015-06-09 at 23:56:59 +0200, Henning Thielemann wrote: [...]
You think about making MonadFail a subclass of Applicative where the name MonadFail becomes misleading - how about naming it Fail instead?
'Fail' would be a good name, if it became an independent class (w/o a superclass to either 'Applicative' or 'Monad'). But the cost for that is having to use `(Fail m, Monad m) =>` Or rely on e.g. constraint synonyms, via e.g. {-# LANGUAGE ConstraintKinds #-} type MonadFail m = (Fail m, Monad m) type ApplicativeFail m = (Fail m, Applicative m) for convenience. I've also heard the suggestion 'FailDo', which could make sense if it became a superclass of Applicative (but then we'd still have to use '(FailDo m, Monad m)' or a constraint-synonym for the majority of cases, where 'fail' is used in a 'Monad' context) Otoh, the reason I suggested to just go w/ 'MonadFail' to keep it simple was that I doubted that that 'fail' in a '-XApplicativeDo' made much sense. But maybe it does make sense? I.e. while 'fail' has laws w/ 'Monad', what would be the respective laws for 'fail' in an 'Applicative' context? Cheers, hvr

On Wed, Jun 10, 2015 at 8:46 AM, Herbert Valerio Riedel
{-# LANGUAGE ConstraintKinds #-} type MonadFail m = (Fail m, Monad m) type ApplicativeFail m = (Fail m, Applicative m)
If we're forced into a situation where we need to factor it into a separate class and build aliases like this, then switching to undecidable instances and encoding that as class (Monad m, Fail m) => MonadFail m instance (Monad m, Fail m) => MonadFail m etc. would be much better than using the ConstraintKinds extension and a type alias. The type synonym you gave doesn't let you use "MonadFail" as a first class inhabitant of kind (* -> *) -> Constraint, you can only pass it once it has been applied to an `m`. This rules out many useful type level tricks. -Edward
_______________________________________________
Libraries mailing list
Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Henning Thielemann wrote:
We should clearly decide what "fail" is intended for - for programming errors or for exceptions. I guess that people want to use it in the second sense, e.g. something like "guard" driven by a pattern match in the Maybe or list monad. But then "fail" must not have an argument because what user related information can the compiler add automatically? Instead of removing the String argument from "fail", the compiler could simply call "mzero" instead.
And then there's ErrorT, which does actually make the information available to the user. I agree that the current situation is a bit messy, but at the same time I believe the choices made for fail make sense and are very convenient. Perhaps more importantly, I see no sane way to "clean up the mess" even if that's desired. We've already had that experience on a small scale, when the Error class constraint was removed from the Monad instance for Either e. The problem with this change was that code kept compiling, but started to raise runtime errors where previously there hadn't been any. Tracking down these uses of Either and replacing them by ErrorT was quite tedious. To summarize, I believe we should keep the current semantics of fail, even if it's moved to a new class. Cheers, Bertram

+1 from me for both the spirit and the substance of this proposal. We've been talking about this in the abstract for a while now (since ICFP 2013 or so) and as concrete plans go, this strikes me as straightforward and implementable. -Edward On Tue, Jun 9, 2015 at 10:43 PM, David Luposchainsky < dluposchainsky@googlemail.com> wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Hello *,
the subject says it all. After we successfully put `=>` into Monad, it is time to remove something in return: `fail`.
Like with the AMP, I wrote up the proposal in Markdown format on Github, which you can find below as a URL, and in verbatim copy at the end of this email. It provides an overview over the intended outcome, which design decisions we had to take, and how our initial plan for the transition looks like. There are also some issues left open to discussion.
https://github.com/quchen/articles/blob/master/monad_fail.md
Here's a short abstract:
- - Move `fail` from `Monad` into a new class `MonadFail`. - - Code using failable patterns will receive a more restrictive `MonadFail` constraint. Code without this constraint will be safe to use for all Monads. - - Transition will take at least two GHC releases. GHC 7.12 will include the new class, and generate warnings asking users to make their failable patterns compliant. - - Stackage showed an upper bound of less than 500 breaking code fragments when compiled with the new desugaring.
For more details, refer to the link or the paste at the end.
Let's get going!
David aka quchen
=============================================================== =============================================================== ===============================================================
`MonadFail` proposal (MFP) ==========================
A couple of years ago, we proposed to make `Applicative` a superclass of `Monad`, which successfully killed the single most ugly thing in Haskell as of GHC 7.10.
Now, it's time to tackle the other major issue with `Monad`: `fail` being a part of it.
You can contact me as usual via IRC/Freenode as *quchen*, or by email to *dluposchainsky at the email service of Google*. This file will also be posted on the ghc-devs@ and libraries@ mailing lists, as well as on Reddit.
Overview - --------
- - **The problem** - reason for the proposal - - **MonadFail class** - the solution - - **Discussion** - explaining our design choices - - **Adapting old code** - how to prepare current code to transition smoothly - - **Esimating the breakage** - how much stuff we will break (spoiler: not much) - - **Transitional strategy** - how to break as little as possible while transitioning - - **Current status**
The problem - -----------
Currently, the `<-` symbol is unconditionally desugared as follows:
```haskell do pat <- computation >>> let f pat = more more >>> f _ = fail "..." >>> in computation >>= f ```
The problem with this is that `fail` cannot (!) be sensibly implemented for many monads, for example `State`, `IO`, `Reader`. In those cases it defaults to `error`. As a consequence, in current Haskell, you can not use `Monad`-polymorphic code safely, because although it claims to work for all `Monad`s, it might just crash on you. This kind of implicit non-totality baked into the class is *terrible*.
The goal of this proposal is adding the `fail` only when necessary and reflecting that in the type signature of the `do` block, so that it can be used safely, and more importantly, is guaranteed not to be used if the type signature does not say so.
`MonadFail` class - -----------------
To fix this, introduce a new typeclass:
```haskell class Monad m => MonadFail m where fail :: String -> m a ```
Desugaring can now be changed to produce this constraint when necessary. For this, we have to decide when a pattern match can not fail; if this is the case, we can omit inserting the `fail` call.
The most trivial examples of unfailable patterns are of course those that match anywhere unconditionally,
```haskell do x <- action >>> let f x = more more >>> in action >>= f ```
In particular, the programmer can assert any pattern be unfailable by making it irrefutable using a prefix tilde:
```haskell do ~pat <- action >>> let f ~pat = more more >>> in action >>= f ```
A class of patterns that are conditionally failable are `newtype`s, and single constructor `data` types, which are unfailable by themselves, but may fail if matching on their fields is done with failable paterns.
```haskell data Newtype a = Newtype a
- -- "x" cannot fail do Newtype x <- action >>> let f (Newtype x) = more more >>> in action >>= f
- -- "Just x" can fail do Newtype (Just x) <- action >>> let f (Newtype (Just x)) = more more >>> f _ = fail "..." >>> in action >>= f ```
`ViewPatterns` are as failable as the pattern the view is matched against. Patterns like `(Just -> Just x)` should generate a `MonadFail` constraint even when it's "obvious" from the view's implementation that the pattern will always match. From an implementor's perspective, this means that only types (and their constructors) have to be looked at, not arbitrary values (like functions), which is impossible to do statically in general.
```haskell do (view -> pat) <- action >>> let f (view -> pat) = more more >>> f _ = fail "..." >>> in action >>= f
do (view -> ~pat) <- action >>> let f (view -> ~pat) = more more >>> in action >>= f ```
A similar issue arises for `PatternSynonyms`, which we cannot inspect during compilation sufficiently. A pattern synonym will therefore always be considered failable.
```haskell do PatternSynonym x <- action >>> let f PatternSynonym x = more more >>> in f _ = fail "..." >>> in action >>= f ```
Discussion - ----------
- - Although for many `MonadPlus` `fail _ = mzero`, a separate `MonadFail` class should be created instead of just using that.
- A parser might fail with an error message involving positional information. Some libraries, like `Binary`, provide `fail` as their only interface to fail a decoding step.
- Although `STM` is `MonadPlus`, it uses the default `fail = error`. It will therefore not get a `MonadFail` instance.
- - What laws should `fail` follow? **Left zero**,
```haskell ∀ s f. fail s >>= f ≡ fail s ```
A call to `fail` should abort the computation. In this sense, `fail` would become a close relative of `mzero`. It would work well with the common definition `fail _ = mzero`, and give a simple guideline to the intended usage and effect of the `MonadFail` class.
- - Rename `fail`? **No.** Old code might use `fail` explicitly and we might avoid breaking it, the Report talks about `fail`, and we have a solid migration strategy that does not require a renaming.
- - Remove the `String` argument? **No.** The `String` might help error reporting and debugging. `String` may be ugly, but it's the de facto standard for simple text in GHC. No high performance string operations are to be expected with `fail`, so this breaking change would in no way be justified. Also note that explicit `fail` calls would break if we removed the argument.
- - How sensitive would existing code be to subtle changes in the strictness behaviour of `do` notation pattern matching? **It doesn't.** The implementation does not affect strictness at all, only the desugaring step. Care must be taken when fixing warnings by making patterns irrefutable using `~`, as that *does* affect strictness. (Cf. difference between lazy/strict State)
- - The `Monad` constraint for `MonadFail` seems unnecessary. Should we drop or relax it? What other things should be considered?
- Applicative `do` notation is coming sooner or later, `fail` might be useful in this more general scenario. Due to the AMP, it is trivial to change the `MonadFail` superclass to `Applicative` later. (The name will be a bit misleading, but it's a very small price to pay.) - The class might be misused for a strange pointed type if left without any constraint. This is not the intended use at all.
I think we should keep the `Monad` superclass for three main reasons:
- We don't want to see `(Monad m, MonadFail m) =>` all over the place. - The primary intended use of `fail` is for desugaring do-notation anyway. - Retroactively removing superclasses is easy, but adding them is hard (see AMP).
Adapting old code - -----------------
- - Help! My code is broken because of a missing `MonadFail` instance!
*Here are your options:*
1. Write a `MonadFail` instance (and bring it into scope)
```haskell #if !MIN_VERSION_base(4,11,0) -- Control.Monad.Fail import will become redundant in GHC 7.16+ import qualified Control.Monad.Fail as Fail #endif import Control.Monad
instance Monad Foo where (>>=) = <...bind impl...> -- NB: `return` defaults to `pure`
#if !MIN_VERSION_base(4,11,0) -- Monad(fail) will be removed in GHC 7.16+ fail = Fail.fail #endif
instance MonadFail Foo where fail = <...fail implementation...> ```
2. Change your pattern to be irrefutable
3. Emulate the old behaviour by desugaring the pattern match by hand:
```haskell do Left e <- foobar stuff ```
becomes
```haskell do x <- foobar e <- case foobar of Left e' -> e' Right r -> error "Pattern match failed" -- Boooo stuff ```
The point is you'll have to do your dirty laundry yourself now if you have a value that *you* know will always match, and if you don't handle the other patterns you'll get incompleteness warnings, and the compiler won't silently eat those for you.
- - Help! My code is broken because you removed `fail` from `Monad`, but my class defines it!
*Delete that part of the instance definition.*
Esimating the breakage - ----------------------
Using our initial implementation, I compiled stackage-nightly, and grepped the logs for found "invalid use of fail desugaring". Assuming my implementation is correct, the number of "missing `MonadFail`" warnings generated is 487. Note that I filtered out `[]`, `Maybe` and `ReadPrec`, since those can be given a `MonadFail` instance from within GHC, and no breakage is expected from them.
The build logs can be found [here][stackage-logs]. Search for "failable pattern" to find your way to the still pretty raw warnings.
Transitional strategy - ---------------------
The roadmap is similar to the [AMP][amp], the main difference being that since `MonadFail` does not exist yet, we have to introduce new functionality and then switch to it.
* **GHC 7.12 / base-4.9**
- Add module `Control.Monad.Fail` with new class `MonadFail(fail)` so people can start writing instances for it.
`Control.Monad` only re-exports the class `MonadFail`, but not its `fail` method.
NB: At this point, `Control.Monad.Fail.fail` clashes with `Prelude.fail` and `Control.Monad.fail`.
- *(non-essential)* Add a language extension `-XMonadFail` that changes desugaring to use `MonadFail(fail)` instead of `Monad(fail)`.
This has the effect that typechecking will infer a `MonadFail` constraint for `do` blocks with failable patterns, just as it is planned to do when the entire thing is done.
- Warn when a `do`-block that contains a failable pattern is desugared, but there is no `MonadFail`-instance in scope: "Please add the instance or change your pattern matching." Add a flag to control whether this warning appears.
- Warn when an instance implements the `fail` function (or when `fail` is imported as a method of `Monad`), as it will be removed from the `Monad` class in the future. (See also [GHC #10071][trac-10071])
3. GHC 7.14
- Switch `-XMonadFail` on by default. - Remove the desugaring warnings.
3. GHC 7.16
- Remove `-XMonadFail`, leaving its effects on at all times. - Remove `fail` from `Monad`. - Instead, re-export `Control.Monad.Fail.fail` as `Prelude.fail` and `Control.Monad.fail`. - `Control.Monad.Fail` is now a redundant module that can be considered deprecated.
Current status - --------------
- - [ZuriHac 2015 (29.5. - 31.5.)][zurihac]: Franz Thoma (@fmthoma) and me (David Luposchainsky aka @quchen) started implementing the MFP in GHC.
- Desugaring to the new `fail` can be controlled via a new langauge extension, `MonadFailDesugaring`. - If the language extension is turned off, a warning will be emitted for code that would break if it was enabled. - Warnings are emitted for types that *have* a *MonadFail* instance. This still needs to be fixed. - The error message are readable, but should be more so. We're still on this. - - 2015-06-09: Estimated breakage by compiling Stackage. Smaller than expected.
[amp]: https://github.com/quchen/articles/blob/master/applicative_monad.md [stackage-logs]: https://www.dropbox.com/s/knz0i979skam4zs/stackage-build.tar.xz?dl=0 [trac-10071]: https://ghc.haskell.org/trac/ghc/ticket/10071 [zurihac]: https://wiki.haskell.org/ZuriHac2015
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1
iQEcBAEBAgAGBQJVd0/yAAoJELrQsaT5WQUshbUH/A3W0itVAk7ao8rtxId5unCJ 7StriKVkTyLAkkrbRJngM4MHEKiCsoyIgr8kBIwSHgk194GxeP2NCF4ijuBZoDBt +Uci+6BCBinV8+OzfrfTcJb4+8iw1j+eLWJ/Nz/JDMDNCiyzyC0SMsqGa+ssOz7H /2mqPkQjQgpHuP5PTRLHKPPIsayCQvTbZR1f14KhuMN2SPDE+WY4rqugu//XuIkN u1YssIf5l8mEez/1ljaqGL55cTI0UNg2z0iA0bFl/ajHaeQ6mc5BAevWfSohAMW7 7PIt13p9NIaMHnikmI+YJszm2IEaXuv47mGgbyDV//nHq3fwWN+naB+1mPX2eSU= =vPAL -----END PGP SIGNATURE----- _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

I'm a +1 on this proposal as well. In our private Haskell compiler at work, we have had separate Monad and MonadFail classes since 2010, and it is clearly the more principled way to handle partiality: make it visible in the inferred types. I found that there were very few instances when porting Hackage libraries to our compiler that we came across a need to change type signatures because of MonadFail, and making the change was in all cases easy anyway. Regards, Malcolm On 9 Jun 2015, at 23:19, Edward Kmett wrote:
+1 from me for both the spirit and the substance of this proposal. We've been talking about this in the abstract for a while now (since ICFP 2013 or so) and as concrete plans go, this strikes me as straightforward and implementable.
-Edward
On Tue, Jun 9, 2015 at 10:43 PM, David Luposchainsky
wrote: -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hello *,
the subject says it all. After we successfully put `=>` into Monad, it is time to remove something in return: `fail`.
Like with the AMP, I wrote up the proposal in Markdown format on Github, which you can find below as a URL, and in verbatim copy at the end of this email. It provides an overview over the intended outcome, which design decisions we had to take, and how our initial plan for the transition looks like. There are also some issues left open to discussion.
https://github.com/quchen/articles/blob/master/monad_fail.md
Here's a short abstract:
- - Move `fail` from `Monad` into a new class `MonadFail`. - - Code using failable patterns will receive a more restrictive `MonadFail` constraint. Code without this constraint will be safe to use for all Monads. - - Transition will take at least two GHC releases. GHC 7.12 will include the new class, and generate warnings asking users to make their failable patterns compliant. - - Stackage showed an upper bound of less than 500 breaking code fragments when compiled with the new desugaring.
For more details, refer to the link or the paste at the end.
Let's get going!
David aka quchen
=============================================================== =============================================================== ===============================================================
`MonadFail` proposal (MFP) ==========================
A couple of years ago, we proposed to make `Applicative` a superclass of `Monad`, which successfully killed the single most ugly thing in Haskell as of GHC 7.10.
Now, it's time to tackle the other major issue with `Monad`: `fail` being a part of it.
You can contact me as usual via IRC/Freenode as *quchen*, or by email to *dluposchainsky at the email service of Google*. This file will also be posted on the ghc-devs@ and libraries@ mailing lists, as well as on Reddit.
Overview - --------
- - **The problem** - reason for the proposal - - **MonadFail class** - the solution - - **Discussion** - explaining our design choices - - **Adapting old code** - how to prepare current code to transition smoothly - - **Esimating the breakage** - how much stuff we will break (spoiler: not much) - - **Transitional strategy** - how to break as little as possible while transitioning - - **Current status**
The problem - -----------
Currently, the `<-` symbol is unconditionally desugared as follows:
```haskell do pat <- computation >>> let f pat = more more >>> f _ = fail "..." >>> in computation >>= f ```
The problem with this is that `fail` cannot (!) be sensibly implemented for many monads, for example `State`, `IO`, `Reader`. In those cases it defaults to `error`. As a consequence, in current Haskell, you can not use `Monad`-polymorphic code safely, because although it claims to work for all `Monad`s, it might just crash on you. This kind of implicit non-totality baked into the class is *terrible*.
The goal of this proposal is adding the `fail` only when necessary and reflecting that in the type signature of the `do` block, so that it can be used safely, and more importantly, is guaranteed not to be used if the type signature does not say so.
`MonadFail` class - -----------------
To fix this, introduce a new typeclass:
```haskell class Monad m => MonadFail m where fail :: String -> m a ```
Desugaring can now be changed to produce this constraint when necessary. For this, we have to decide when a pattern match can not fail; if this is the case, we can omit inserting the `fail` call.
The most trivial examples of unfailable patterns are of course those that match anywhere unconditionally,
```haskell do x <- action >>> let f x = more more >>> in action >>= f ```
In particular, the programmer can assert any pattern be unfailable by making it irrefutable using a prefix tilde:
```haskell do ~pat <- action >>> let f ~pat = more more >>> in action >>= f ```
A class of patterns that are conditionally failable are `newtype`s, and single constructor `data` types, which are unfailable by themselves, but may fail if matching on their fields is done with failable paterns.
```haskell data Newtype a = Newtype a
- -- "x" cannot fail do Newtype x <- action >>> let f (Newtype x) = more more >>> in action >>= f
- -- "Just x" can fail do Newtype (Just x) <- action >>> let f (Newtype (Just x)) = more more >>> f _ = fail "..." >>> in action >>= f ```
`ViewPatterns` are as failable as the pattern the view is matched against. Patterns like `(Just -> Just x)` should generate a `MonadFail` constraint even when it's "obvious" from the view's implementation that the pattern will always match. From an implementor's perspective, this means that only types (and their constructors) have to be looked at, not arbitrary values (like functions), which is impossible to do statically in general.
```haskell do (view -> pat) <- action >>> let f (view -> pat) = more more >>> f _ = fail "..." >>> in action >>= f
do (view -> ~pat) <- action >>> let f (view -> ~pat) = more more >>> in action >>= f ```
A similar issue arises for `PatternSynonyms`, which we cannot inspect during compilation sufficiently. A pattern synonym will therefore always be considered failable.
```haskell do PatternSynonym x <- action >>> let f PatternSynonym x = more more >>> in f _ = fail "..." >>> in action >>= f ```
Discussion - ----------
- - Although for many `MonadPlus` `fail _ = mzero`, a separate `MonadFail` class should be created instead of just using that.
- A parser might fail with an error message involving positional information. Some libraries, like `Binary`, provide `fail` as their only interface to fail a decoding step.
- Although `STM` is `MonadPlus`, it uses the default `fail = error`. It will therefore not get a `MonadFail` instance.
- - What laws should `fail` follow? **Left zero**,
```haskell ∀ s f. fail s >>= f ≡ fail s ```
A call to `fail` should abort the computation. In this sense, `fail` would become a close relative of `mzero`. It would work well with the common definition `fail _ = mzero`, and give a simple guideline to the intended usage and effect of the `MonadFail` class.
- - Rename `fail`? **No.** Old code might use `fail` explicitly and we might avoid breaking it, the Report talks about `fail`, and we have a solid migration strategy that does not require a renaming.
- - Remove the `String` argument? **No.** The `String` might help error reporting and debugging. `String` may be ugly, but it's the de facto standard for simple text in GHC. No high performance string operations are to be expected with `fail`, so this breaking change would in no way be justified. Also note that explicit `fail` calls would break if we removed the argument.
- - How sensitive would existing code be to subtle changes in the strictness behaviour of `do` notation pattern matching? **It doesn't.** The implementation does not affect strictness at all, only the desugaring step. Care must be taken when fixing warnings by making patterns irrefutable using `~`, as that *does* affect strictness. (Cf. difference between lazy/strict State)
- - The `Monad` constraint for `MonadFail` seems unnecessary. Should we drop or relax it? What other things should be considered?
- Applicative `do` notation is coming sooner or later, `fail` might be useful in this more general scenario. Due to the AMP, it is trivial to change the `MonadFail` superclass to `Applicative` later. (The name will be a bit misleading, but it's a very small price to pay.) - The class might be misused for a strange pointed type if left without any constraint. This is not the intended use at all.
I think we should keep the `Monad` superclass for three main reasons:
- We don't want to see `(Monad m, MonadFail m) =>` all over the place. - The primary intended use of `fail` is for desugaring do-notation anyway. - Retroactively removing superclasses is easy, but adding them is hard (see AMP).
Adapting old code - -----------------
- - Help! My code is broken because of a missing `MonadFail` instance!
*Here are your options:*
1. Write a `MonadFail` instance (and bring it into scope)
```haskell #if !MIN_VERSION_base(4,11,0) -- Control.Monad.Fail import will become redundant in GHC 7.16+ import qualified Control.Monad.Fail as Fail #endif import Control.Monad
instance Monad Foo where (>>=) = <...bind impl...> -- NB: `return` defaults to `pure`
#if !MIN_VERSION_base(4,11,0) -- Monad(fail) will be removed in GHC 7.16+ fail = Fail.fail #endif
instance MonadFail Foo where fail = <...fail implementation...> ```
2. Change your pattern to be irrefutable
3. Emulate the old behaviour by desugaring the pattern match by hand:
```haskell do Left e <- foobar stuff ```
becomes
```haskell do x <- foobar e <- case foobar of Left e' -> e' Right r -> error "Pattern match failed" -- Boooo stuff ```
The point is you'll have to do your dirty laundry yourself now if you have a value that *you* know will always match, and if you don't handle the other patterns you'll get incompleteness warnings, and the compiler won't silently eat those for you.
- - Help! My code is broken because you removed `fail` from `Monad`, but my class defines it!
*Delete that part of the instance definition.*
Esimating the breakage - ----------------------
Using our initial implementation, I compiled stackage-nightly, and grepped the logs for found "invalid use of fail desugaring". Assuming my implementation is correct, the number of "missing `MonadFail`" warnings generated is 487. Note that I filtered out `[]`, `Maybe` and `ReadPrec`, since those can be given a `MonadFail` instance from within GHC, and no breakage is expected from them.
The build logs can be found [here][stackage-logs]. Search for "failable pattern" to find your way to the still pretty raw warnings.
Transitional strategy - ---------------------
The roadmap is similar to the [AMP][amp], the main difference being that since `MonadFail` does not exist yet, we have to introduce new functionality and then switch to it.
* **GHC 7.12 / base-4.9**
- Add module `Control.Monad.Fail` with new class `MonadFail(fail)` so people can start writing instances for it.
`Control.Monad` only re-exports the class `MonadFail`, but not its `fail` method.
NB: At this point, `Control.Monad.Fail.fail` clashes with `Prelude.fail` and `Control.Monad.fail`.
- *(non-essential)* Add a language extension `-XMonadFail` that changes desugaring to use `MonadFail(fail)` instead of `Monad(fail)`.
This has the effect that typechecking will infer a `MonadFail` constraint for `do` blocks with failable patterns, just as it is planned to do when the entire thing is done.
- Warn when a `do`-block that contains a failable pattern is desugared, but there is no `MonadFail`-instance in scope: "Please add the instance or change your pattern matching." Add a flag to control whether this warning appears.
- Warn when an instance implements the `fail` function (or when `fail` is imported as a method of `Monad`), as it will be removed from the `Monad` class in the future. (See also [GHC #10071][trac-10071])
3. GHC 7.14
- Switch `-XMonadFail` on by default. - Remove the desugaring warnings.
3. GHC 7.16
- Remove `-XMonadFail`, leaving its effects on at all times. - Remove `fail` from `Monad`. - Instead, re-export `Control.Monad.Fail.fail` as `Prelude.fail` and `Control.Monad.fail`. - `Control.Monad.Fail` is now a redundant module that can be considered deprecated.
Current status - --------------
- - [ZuriHac 2015 (29.5. - 31.5.)][zurihac]: Franz Thoma (@fmthoma) and me (David Luposchainsky aka @quchen) started implementing the MFP in GHC.
- Desugaring to the new `fail` can be controlled via a new langauge extension, `MonadFailDesugaring`. - If the language extension is turned off, a warning will be emitted for code that would break if it was enabled. - Warnings are emitted for types that *have* a *MonadFail* instance. This still needs to be fixed. - The error message are readable, but should be more so. We're still on this. - - 2015-06-09: Estimated breakage by compiling Stackage. Smaller than expected.
[amp]: https://github.com/quchen/articles/blob/master/applicative_monad.md [stackage-logs]: https://www.dropbox.com/s/knz0i979skam4zs/stackage-build.tar.xz?dl=0 [trac-10071]: https://ghc.haskell.org/trac/ghc/ticket/10071 [zurihac]: https://wiki.haskell.org/ZuriHac2015
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1
iQEcBAEBAgAGBQJVd0/yAAoJELrQsaT5WQUshbUH/A3W0itVAk7ao8rtxId5unCJ 7StriKVkTyLAkkrbRJngM4MHEKiCsoyIgr8kBIwSHgk194GxeP2NCF4ijuBZoDBt +Uci+6BCBinV8+OzfrfTcJb4+8iw1j+eLWJ/Nz/JDMDNCiyzyC0SMsqGa+ssOz7H /2mqPkQjQgpHuP5PTRLHKPPIsayCQvTbZR1f14KhuMN2SPDE+WY4rqugu//XuIkN u1YssIf5l8mEez/1ljaqGL55cTI0UNg2z0iA0bFl/ajHaeQ6mc5BAevWfSohAMW7 7PIt13p9NIaMHnikmI+YJszm2IEaXuv47mGgbyDV//nHq3fwWN+naB+1mPX2eSU= =vPAL -----END PGP SIGNATURE----- _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Thanks for putting this together. The proposal says: "As a consequence, in current Haskell, you can not use Monad-polymorphic code safely, because although it claims to work for all Monads, it might just crash on you. This kind of implicit non-totality baked into the class is terrible." Is this actually a problem in practice? Is there any code we can point to that suffers because of the current state of affairs? Could it be included in the proposal?

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 10.06.2015 00:26, Johan Tibell wrote:
"As a consequence, in current Haskell, you can not use Monad-polymorphic code safely, because although it claims to work for all Monads, it might just crash on you. This kind of implicit non-totality baked into the class is terrible."
Is this actually a problem in practice? Is there any code we can point to that suffers because of the current state of affairs? Could it be included in the proposal?
I don't have hard evidence, but the Monad class being partial strikes me as pretty backwards in a language where totality and no implicit failures are important to the programmers. We try our best to advocate not using certain functions like "head" carelessly, but do-notation comes with similar partiality. One concrete example that I know is bimap, but that's something I stumbled upon months ago by accident. Another is that Binary does not have a monomorphic "fail" function and it hurts me a bit to use the Monad-"fail" and write a comment on how that is safe to do in the current context. I think there are two important consequences of MonadFail. First of all, we can all safely write failable patterns if we so desire. Second, the compiler can ensure other people's codebases do not lie to us (knowingly or unknowingly). David/quchen -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAEBAgAGBQJVd2vEAAoJELrQsaT5WQUs+m8IAOWA9Hd52MG1wZ6g6FoOcXd6 x64dRDlilmkVu2IRxHADzip75Oji254yKQ5VY9yMGjYpFajtgf0Q8LrmA0ePTzhg E/oxdm1vyRoJab1C5TfdrzPM/voP+wHi7y2ak1j0hTNky+wETj4MKtJ/Jef225nd APUq05t6nPwzEDCz37RitfbA6/nwwYShaVjNe0tRluPrJuxdBu0+aobFc2lzVL+s J7egnV1kqEOhc7INOhWYsvAJPAJSiY950y/Nmxb2/r5orTfN3tsr98d1zwRxhCmq UNXhUaj5xD7BK2Rn1Zy7VwUv1T8IRLZuOQrlZh3HWz4t1SI0tTu3tdS468s/B1g= =4mEU -----END PGP SIGNATURE-----

+1. This sounds like a good change and, for the most part, doesn't seem all that painful. As far as naming goes, perhaps we could make the name refer to do-notation? Something like DoFail. I mean, that doesn't sound great, but it makes it clear where fail comes in and how it might apply to non-monad type stuff. (ApplicativeDo, for example?) It's also good because nothing about fail is integral to the abstract idea of a monad or even an applicative. It's a function of convenience to make pattern matches in do-notation play out better in cases where it's meaningful. That's true in the other direction too: nothing about a `fail` function is particularly tied to monads or even applicatives. A Monad/Applicative superclass might make the desugaring easier and closer to current behavior, but the idea of a fail :: String -> f a is broadly applicable to fs that aren't necessarily either of those. On Tue, Jun 9, 2015 at 3:42 PM, David Luposchainsky < dluposchainsky@googlemail.com> wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 10.06.2015 00:26, Johan Tibell wrote:
"As a consequence, in current Haskell, you can not use Monad-polymorphic code safely, because although it claims to work for all Monads, it might just crash on you. This kind of implicit non-totality baked into the class is terrible."
Is this actually a problem in practice? Is there any code we can point to that suffers because of the current state of affairs? Could it be included in the proposal?
I don't have hard evidence, but the Monad class being partial strikes me as pretty backwards in a language where totality and no implicit failures are important to the programmers. We try our best to advocate not using certain functions like "head" carelessly, but do-notation comes with similar partiality.
One concrete example that I know is bimap, but that's something I stumbled upon months ago by accident. Another is that Binary does not have a monomorphic "fail" function and it hurts me a bit to use the Monad-"fail" and write a comment on how that is safe to do in the current context.
I think there are two important consequences of MonadFail. First of all, we can all safely write failable patterns if we so desire. Second, the compiler can ensure other people's codebases do not lie to us (knowingly or unknowingly).
David/quchen -----BEGIN PGP SIGNATURE----- Version: GnuPG v1
iQEcBAEBAgAGBQJVd2vEAAoJELrQsaT5WQUs+m8IAOWA9Hd52MG1wZ6g6FoOcXd6 x64dRDlilmkVu2IRxHADzip75Oji254yKQ5VY9yMGjYpFajtgf0Q8LrmA0ePTzhg E/oxdm1vyRoJab1C5TfdrzPM/voP+wHi7y2ak1j0hTNky+wETj4MKtJ/Jef225nd APUq05t6nPwzEDCz37RitfbA6/nwwYShaVjNe0tRluPrJuxdBu0+aobFc2lzVL+s J7egnV1kqEOhc7INOhWYsvAJPAJSiY950y/Nmxb2/r5orTfN3tsr98d1zwRxhCmq UNXhUaj5xD7BK2Rn1Zy7VwUv1T8IRLZuOQrlZh3HWz4t1SI0tTu3tdS468s/B1g= =4mEU -----END PGP SIGNATURE----- _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

On 2015-06-10 at 00:42:12 +0200, David Luposchainsky wrote: [...]
I think there are two important consequences of MonadFail. First of all, we can all safely write failable patterns if we so desire. Second, the compiler can ensure other people's codebases do not lie to us (knowingly or unknowingly).
...as a data-point, when turning on MonadFail during testing, I've seen at least one place in GHC's own code-base that directly calls 'fail' for a Monad instance which did *not* have its 'fail' method overridden. Moreover, I've seen at least one (other) case, where failable pattern matches occurred (intentionally or not[1]), but the respective Monad instance didn't have the 'fail' method overridden either. [1]: Failable patterns can in theory snuck in non-intentionally, e.g. they can be introduced during refactoring if e.g. a single-constructor type gets added new constructors. If the context was previously constraint to a 'Monad', after the refactoring the typechecker would point out that now there's a failable pattern not accounted for.

On Wed, Jun 10, 2015 at 12:42 AM, David Luposchainsky < dluposchainsky@googlemail.com> wrote:
I think there are two important consequences of MonadFail. First of all, we can all safely write failable patterns if we so desire. Second, the compiler can ensure other people's codebases do not lie to us (knowingly or unknowingly).
The second is a bit overstated I think. Any function you call can still have partial pattern matches in all the other places Haskell allows them and you wouldn't know from the type.

On Wed, 10 Jun 2015, David Luposchainsky wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 10.06.2015 00:26, Johan Tibell wrote:
"As a consequence, in current Haskell, you can not use Monad-polymorphic code safely, because although it claims to work for all Monads, it might just crash on you. This kind of implicit non-totality baked into the class is terrible."
Is this actually a problem in practice? Is there any code we can point to that suffers because of the current state of affairs? Could it be included in the proposal?
I don't have hard evidence, but the Monad class being partial strikes me as pretty backwards in a language where totality and no implicit failures are important to the programmers. We try our best to advocate not using certain functions like "head" carelessly, but do-notation comes with similar partiality.
As far as I remember, I have never implemented 'fail' in the Monad instances I wrote over the years. Thus, splitting off MonadFail would reward me with more precise type signatures: The constraint (Monad m) would prevent people from calling 'fail' which I have never implemented.

I can give a couple of "rather academic" issues that the status quo causes:
An example of where this has bit us in the hindquarters in the past is that
the old Error class based instance for Monad (Either a) from the mtl
incurred a constraint on the entire Monad instance in order to support
'fail'.
This ruled out many applications for the Either monad, e.g. apo/gapo are
based on the real (Either e) monad, just as para/zygo are based on the
"real" ((,) e) comonad. This rather complicated the use of recursion
schemes and in fact was what drove me to write what turned into the
"either" package in the first place.
Now we don't try to support 'fail' at all for that Monad. Under this
proposal though, one _could_ add a MonadFail instance that incurred a
rather ad hoc constraint on the left hand side of the sum without
encumbering the Monad itself.
In general you have no way of knowing that you stick to the product-like
structure of the Monad in the current ecosystem, because 'fail' is always
there, you can get to values in the Monad you couldn't reach with just
return and (>>=).
Ideally you'd have (forall m. Monad m => m a) being isomorphic to a, this
can be useful for ensuring we can plumb user-defined effects through code:
http://comonad.com/reader/2011/searching-infinity/
but in Haskell as it exists today you always have to worry about it
invoking a call to fail, and having a special form of _distinguishable_
bottom available from that computation so it is really more like `Either
String a`.
Can you just say "don't do that?"
Sure, but it is the moral equivalent of programming with nulls all over
your code.
-Edward
On Wed, Jun 10, 2015 at 12:26 AM, Johan Tibell
Thanks for putting this together.
The proposal says:
"As a consequence, in current Haskell, you can not use Monad-polymorphic code safely, because although it claims to work for all Monads, it might just crash on you. This kind of implicit non-totality baked into the class is terrible."
Is this actually a problem in practice? Is there any code we can point to that suffers because of the current state of affairs? Could it be included in the proposal?
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

+1, even more so after the not-so-academic issues pointed out by Edward. Cheers, -- Felipe.

+1 to taking fail out of Monad. +0 to any particular failure class;
the issues seem a bit complex, and I haven't studied them closely
enough to have an opinion.
On Tue, Jun 9, 2015 at 10:01 PM, Felipe Lessa
+1, even more so after the not-so-academic issues pointed out by Edward.
Cheers,
-- Felipe.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

On 09/06/2015 23:26, Johan Tibell wrote:
Thanks for putting this together.
The proposal says:
"As a consequence, in current Haskell, you can not use Monad-polymorphic code safely, because although it claims to work for all Monads, it might just crash on you. This kind of implicit non-totality baked into the class is terrible."
Is this actually a problem in practice? Is there any code we can point to that suffers because of the current state of affairs? Could it be included in the proposal?
Here's a concrete example: https://mail.haskell.org/pipermail/libraries/2015-March/025166.html I needed to change some code that used a monad with an explicit fail to use one without, and I couldn't get the compiler to tell me if it was using partial pattern matches or not. If it had been then the refactoring would have caused a nasty behaviour change. Ganesh

i'll add my token +1 to the land slide
On Tue, Jun 9, 2015 at 11:19 PM, Bardur Arantsson
On 06/09/2015 10:43 PM, David Luposchainsky wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
+1
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

+1
Been dreaming about this for so long!
2015-06-10 7:27 GMT+03:00 Carter Schonwald
i'll add my token +1 to the land slide
On Tue, Jun 9, 2015 at 11:19 PM, Bardur Arantsson
wrote: On 06/09/2015 10:43 PM, David Luposchainsky wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
+1
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

+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.

An idea. Could the new desugaring be the same as for normal functions with a missing case? Code that uses fail would have to add the constraint still, but code that really didn't want to use fail would 1) get a warning about an incomplete pattern match and 2) get a runtime error for the failed pattern match produced by GHC. Is there anything I'm not thinking of here why this wouldn't work?

That would make it impossible to have a failed pattern match become an
automatic 'fail' with a MonadFail constraint, right? I think that's a
pretty nice feature, actually. But perhaps I misunderstand your idea.
Erik
On Wed, Jun 10, 2015 at 3:00 PM, Johan Tibell
An idea. Could the new desugaring be the same as for normal functions with a missing case? Code that uses fail would have to add the constraint still, but code that really didn't want to use fail would 1) get a warning about an incomplete pattern match and 2) get a runtime error for the failed pattern match produced by GHC. Is there anything I'm not thinking of here why this wouldn't work?
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

I don't quite follow how that would work in a way that doesn't violate the
open world assumption.
If you pattern match in a do-binding and don't have a MonadFail instance in
scope you'd get a different desugaring?
This would make the presence / absence of an instance change code
generation. Adding instances shouldn't change generated code.
-Edward
On Wed, Jun 10, 2015 at 3:00 PM, Johan Tibell
An idea. Could the new desugaring be the same as for normal functions with a missing case? Code that uses fail would have to add the constraint still, but code that really didn't want to use fail would 1) get a warning about an incomplete pattern match and 2) get a runtime error for the failed pattern match produced by GHC. Is there anything I'm not thinking of here why this wouldn't work?
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

But what is the inferred type for f x = do { [v] <- x, return v } I think the proposal is to have a MonadFail constraint. As far as I understand what you are saying, it would make sense for f :: Monad m => m [a] -> m a g x = do { [v] <- x; return v } (with failure giving a runtime error). From: Libraries [mailto:libraries-bounces@haskell.org] On Behalf Of Johan Tibell Sent: 10 June 2015 14:01 To: Mario Blažević Cc: Haskell Libraries Subject: Re: MonadFail proposal (MFP): Moving fail out of Monad An idea. Could the new desugaring be the same as for normal functions with a missing case? Code that uses fail would have to add the constraint still, but code that really didn't want to use fail would 1) get a warning about an incomplete pattern match and 2) get a runtime error for the failed pattern match produced by GHC. Is there anything I'm not thinking of here why this wouldn't work?

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ć
+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@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

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
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ć
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@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

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
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
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ć
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@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

On Wed, Jun 10, 2015 at 11:44 AM, David Feuer
It therefore seems really only to be suitable for pattern match failure and user-generated IOErrors
I feel like even that second one is not really appropriate. If you want a user-generated IOError, create one yourself; don't make assumptions about availability or API for what should really be considered a compiler or language implementation detail. -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

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
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.
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
On Wed, Jun 10, 2015 at 10:55 AM, Edward Kmett
wrote: 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
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ć
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@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

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
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
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
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
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ć
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@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

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
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
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
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
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
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ć
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@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

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
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
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.
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
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
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
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
On Wed, Jun 10, 2015 at 11:53 AM, Edward Kmett
wrote: base. 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
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@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@haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

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

Hi David, thank you very much for this proposal. I think having fail in Monad is just plain wrong, and I am therefore very happy to see it being moved out. I have some remarks, though:
A class of patterns that are conditionally failable are `newtype`s, and single constructor `data` types, which are unfailable by themselves, but may fail if matching on their fields is done with failable paterns.
The part about single-constructor data types is not true. A single-constructor data type has a value ⊥ that is different from applying the data constructor to ⊥’s. For example, ⊥ and (⊥, ⊥) are two different values. Matching ⊥ against the pattern (_, _) fails, matching (⊥, ⊥) against (_, _) succeeds. So single-constructor data types are not different from all other data types in this respect. The dividing line really runs between data types and newtypes. So only matches against patterns C p where C is a newtype constructor and p is unfailable should be considered unfailable.
- Applicative `do` notation is coming sooner or later, `fail` might be useful in this more general scenario. Due to the AMP, it is trivial to change the `MonadFail` superclass to `Applicative` later. (The name will be a bit misleading, but it's a very small price to pay.)
I think it would be very misleading having a MonadFail class that might have instances that are not monads, and that this is a price we should not pay. So we should not name the class MonadFail. Maybe, Fail would be a good name.
I think we should keep the `Monad` superclass for three main reasons:
- We don't want to see `(Monad m, MonadFail m) =>` all over the place.
But exactly this will happen if we change the superclass of (Monad)Fail from Monad to Applicative. So it might be better to impose a more light-weight constraint in the first place. Functor m might be a good choice. All the best, Wolfgang

On 11-06-2015 12:08, Wolfgang Jeltsch wrote:
A class of patterns that are conditionally failable are `newtype`s, and single constructor `data` types, which are unfailable by themselves, but may fail if matching on their fields is done with failable paterns.
The part about single-constructor data types is not true. A single-constructor data type has a value ⊥ that is different from applying the data constructor to ⊥’s. For example, ⊥ and (⊥, ⊥) are two different values. Matching ⊥ against the pattern (_, _) fails, matching (⊥, ⊥) against (_, _) succeeds. So single-constructor data types are not different from all other data types in this respect. The dividing line really runs between data types and newtypes. So only matches against patterns C p where C is a newtype constructor and p is unfailable should be considered unfailable.
I think that being failable is a property that is undefined for undefined. Ok, sorry :), what I mean is that you can't do anything to distinguish C p from _|_ within pure code. For example: Just a <- x You can distinguish Just a from Nothing in pure code, so that gets translated to a pattern match and a fail call. However: (a, b) <- x You can't distinguish (a, b) from _|_. In other words, the pattern (a, b) covers every possible value of its type. So it doesn't need a fail call. And it doesn't matter if it's a newtype or a single-constructor data type. Makes sense? Cheers, -- Felipe.

Am Donnerstag, den 11.06.2015, 12:15 -0300 schrieb Felipe Lessa:
On 11-06-2015 12:08, Wolfgang Jeltsch wrote:
A class of patterns that are conditionally failable are `newtype`s, and single constructor `data` types, which are unfailable by themselves, but may fail if matching on their fields is done with failable paterns.
The part about single-constructor data types is not true. A single-constructor data type has a value ⊥ that is different from applying the data constructor to ⊥’s. For example, ⊥ and (⊥, ⊥) are two different values. Matching ⊥ against the pattern (_, _) fails, matching (⊥, ⊥) against (_, _) succeeds. So single-constructor data types are not different from all other data types in this respect. The dividing line really runs between data types and newtypes. So only matches against patterns C p where C is a newtype constructor and p is unfailable should be considered unfailable.
I think that being failable is a property that is undefined for undefined. Ok, sorry :), what I mean is that you can't do anything to distinguish C p from _|_ within pure code.
For example:
Just a <- x
You can distinguish Just a from Nothing in pure code, so that gets translated to a pattern match and a fail call.
However:
(a, b) <- x
You can't distinguish (a, b) from _|_. In other words, the pattern (a, b) covers every possible value of its type. So it doesn't need a fail call. And it doesn't matter if it's a newtype or a single-constructor data type. Makes sense?
Well, the pattern (a, b) does not cover every possible value, but every non-⊥ value, but you cannot use pattern matching to choose a different branch for ⊥, since matching ⊥ against any refutable pattern, like (a, b), results in a runtime error. Makes sense. :-) All the best, Wolfgang

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 On 09/06/15 22:43, David Luposchainsky wrote:
- - Move `fail` from `Monad` into a new class `MonadFail`. +1.
Alexander alexander@plaimi.net https://secure.plaimi.net/~alexander -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAEBCgAGBQJVetq6AAoJENQqWdRUGk8B1xoQAPQDm/U9kCOkZK2K8sDWtPTA eUC6Y7xCScYF2SM70gsGvGxqSzk6TxQWTshKkcBIskdgrN8bwW+v20gC2gmfAlh8 CbjtRdozVI54Hjh0Q/dflF7NK8ohRCEAxN4WjwhAkXwuN9WOnNKCUbASGmyjckve z+tY4F17L0hhtAYR7bjZEDjsv6+9FZMvQW6/Az/O/DBihZX/o5MpD9YZ99Bw7hUK oLKEnpNZJwLOkHgPtTJn9V/qUuL3XgXC/lGPP2DmaMPyTrINux2CNhLGHDhPgq9H fvLhehCNT+JVGjAaWqy9y+eUX+9lqZc8u/N+jrnFLteacMF/vEbhjerxbhmDqgKn VRBQqJ3sNeCquZzeXUjfYZkgkl3AL7DRuEUZ5n3wXTACvOjYUqc2JZ3Mb3uhC0bM XbCz3SHdP05x9QSYRh+SWWMNKMSfChOMg3ae6nNd8BWtKr/v2kwPxp2D97yTAPKn lrwR3xdKxs1VN6MALAfFtj7MZWMruFSfhHzZeGmEPZgx/0BU1e2/3VW/JXkA/wOm tOn2l6N9gyuFpSScbfiZmlzCz2AXJ/pCFYlPMOYIN1NCb9T1sHQSYVbG+mf+wgU2 QIcMAP/gJCvAAIg+VKfEpK0TJnQWeQx0OfQABM5A359TezTIYXN4MZ6ZVhZVo2vg 0LDiJjXCCg/I6H6lige8 =H6Um -----END PGP SIGNATURE-----

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 MonadFail proposal update 1 =========================== Rendered version of this text: https://github.com/quchen/articles/blob/master/monad_fail_update1.md Original MFP: https://github.com/quchen/articles/blob/master/monad_fail.md Short summary - ------------- A week has passed since I posted the MFP, and the initial discussion is mostly over. Here are my observations: - - Everyone agrees that `fail` should not be in `Monad`. - - Almost everyone agrees that it should be thrown out of it. - - Some would prefer to see the special desugaring be gone entirely. - - The name `MonadFail` is controversial, because of a potential `Applicative` constraint. - - We're still unsure about whether `IO` should get a `MonadFail` instance, but the bias seems to be towards "yes". New ideas worth thinking about - ------------------------------ ### Special desugaring or not Johann suggested an optional warning whenever something desugars to use `fail`. I think that's an idea we should think about. It is easily implemented in the compiler, and would probably behave similar to -fwarn-unused-do-binds in practice: notation that is not wrong, but might not be what the programmer intended. ### Errors vs. Exceptions Henning is concerned about the confusion between exceptions and programming errors. In his words,
We should clearly decide what "fail" is intended for - for programming errors or for exceptions.
What I see clashing with his point is backwards compatibility. Removing the `String` argument breaks all explicit invocations of `fail`. Unfortunately, we're not in a position to break very much. If someone has a better idea I'd love to hear about it though. ### ApplicativeDo ApplicativeDo is somewhere out there on the horizon, and we're not sure yet how much `fail` makes sense in the context of `Applicative`. An Applicative computation is statically determined in its shape, so it either always or never fails. Depending on previous results would introduce the `Monad` constraint anyway. Probing status - -------------- Henning has started to look at the impact of the proposal when explicit invocations of `fail` are considered as well, something I have not done in my original survey. Luckily, things don't look too bad, Lens and its forest of dependencies can be fixed in around ten trivial changes, for example. Greetings, David/quchen -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAEBAgAGBQJVgDvGAAoJELrQsaT5WQUspmIIAJi9UVYIitHv2CKvWSmk1fg0 hYaPRXDJMnyFS21v57+JeTPhM/dnI4k0guUUrlIB9k5WPaySQ6MKIAnB51o5O9Gv zt87FII5/oYsJtVPruKgBtLPbJVhg6zGUXmNco1S2wvB5m5HdBooQsiBRY+qiFfZ MJOdzXpRCrYJk/0PeF7sglBOElSwsSmGq/klvJUo4VeVAdi8bU+lKRfET/AmAAM5 oqckAI0SEaFo+w6EXBLPiL/F5SoFBmKR50Nu4NKWRBcoNGq7AwvWEKDZeU0PvC3a dykqSnFTRtL5LeWZnByuZTVVqlDG3afjX6ZYkrUbMKQeE9rVf24Gx9jlRusxSds= =zUDu -----END PGP SIGNATURE-----

There is a bit of a knee-jerk reaction that we should go to something simpler than Monad as a superclass constraint for MonadFail, but I think most of those reasons fall apart or at least lose much of their weight upon deeper inspection. Ultimately, I'm a not concerned about interactions between ApplicativeDo notation and fail. Any automatic desugaring into 'fail' will be in a context which is necessarily incurring a monad constraint. E.g. do Just x <- m ... has to pick up the Monad constraint anyways to deal with the binding! This leaves only code that does something like. foo = x <*> fail y which is hand written to invoke fail. Given that the entire "tree" of the Applicative" is available for inspection and that that fail can't depend on any context internal to the Applicative and remain 'just Applicative' I have a hard time foreseeing any real applications lost by continuing to assume a context of: class Monad m => MonadFail m and there is a lot of value in the simple context. Most of the value in ApplicativeDo notation comes from the opportunities for increased parallelism, not so much from the reduced constraints on the resulting code, and as we can see above, it'll never arise during the desguaring in a place that wouldn't incur a Monad constraint anyways. Even getting rid of the Monad constraint w/ ApplicativeDo is going to require gymnastics around `return`. -Edward P.S. On an unrelated note, for the record, I'm very strongly +1 on a MonadFail instance for IO. There we use throwIO explicitly, so it is even able to be handled and caught locally. The set of things you can do in IO is large enough to support and reason about explicit failure. P.P.S. I think if we extend the proposal to include an explicit member of the class for pattern match failure with the code we currently have lurking in the compiler for producing the string from the context, then most of the concerns raised by folks who would prefer to use a heavier weight -- but vastly harder to standardize -- exception mechanism would also be addressed in practice. On Tue, Jun 16, 2015 at 11:07 AM, David Luposchainsky < dluposchainsky@googlemail.com> wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
MonadFail proposal update 1 ===========================
Rendered version of this text: https://github.com/quchen/articles/blob/master/monad_fail_update1.md
Original MFP: https://github.com/quchen/articles/blob/master/monad_fail.md
Short summary - -------------
A week has passed since I posted the MFP, and the initial discussion is mostly over. Here are my observations:
- - Everyone agrees that `fail` should not be in `Monad`. - - Almost everyone agrees that it should be thrown out of it. - - Some would prefer to see the special desugaring be gone entirely. - - The name `MonadFail` is controversial, because of a potential `Applicative` constraint. - - We're still unsure about whether `IO` should get a `MonadFail` instance, but the bias seems to be towards "yes".
New ideas worth thinking about - ------------------------------
### Special desugaring or not
Johann suggested an optional warning whenever something desugars to use `fail`. I think that's an idea we should think about. It is easily implemented in the compiler, and would probably behave similar to -fwarn-unused-do-binds in practice: notation that is not wrong, but might not be what the programmer intended.
### Errors vs. Exceptions
Henning is concerned about the confusion between exceptions and programming errors. In his words,
We should clearly decide what "fail" is intended for - for programming errors or for exceptions.
What I see clashing with his point is backwards compatibility. Removing the `String` argument breaks all explicit invocations of `fail`. Unfortunately, we're not in a position to break very much. If someone has a better idea I'd love to hear about it though.
### ApplicativeDo
ApplicativeDo is somewhere out there on the horizon, and we're not sure yet how much `fail` makes sense in the context of `Applicative`. An Applicative computation is statically determined in its shape, so it either always or never fails. Depending on previous results would introduce the `Monad` constraint anyway.
Probing status - --------------
Henning has started to look at the impact of the proposal when explicit invocations of `fail` are considered as well, something I have not done in my original survey. Luckily, things don't look too bad, Lens and its forest of dependencies can be fixed in around ten trivial changes, for example.
Greetings, David/quchen -----BEGIN PGP SIGNATURE----- Version: GnuPG v1
iQEcBAEBAgAGBQJVgDvGAAoJELrQsaT5WQUspmIIAJi9UVYIitHv2CKvWSmk1fg0 hYaPRXDJMnyFS21v57+JeTPhM/dnI4k0guUUrlIB9k5WPaySQ6MKIAnB51o5O9Gv zt87FII5/oYsJtVPruKgBtLPbJVhg6zGUXmNco1S2wvB5m5HdBooQsiBRY+qiFfZ MJOdzXpRCrYJk/0PeF7sglBOElSwsSmGq/klvJUo4VeVAdi8bU+lKRfET/AmAAM5 oqckAI0SEaFo+w6EXBLPiL/F5SoFBmKR50Nu4NKWRBcoNGq7AwvWEKDZeU0PvC3a dykqSnFTRtL5LeWZnByuZTVVqlDG3afjX6ZYkrUbMKQeE9rVf24Gx9jlRusxSds= =zUDu -----END PGP SIGNATURE----- _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

On this issue I totally agree with Ed. ☺
From: Libraries [mailto:libraries-bounces@haskell.org] On Behalf Of Edward Kmett
Sent: 17 June 2015 14:34
To: David Luposchainsky
Cc: Haskell Libraries; ghc-devs@haskell.org
Subject: Re: MFP updates: ideas worth discussing
There is a bit of a knee-jerk reaction that we should go to something simpler than Monad as a superclass constraint for MonadFail, but I think most of those reasons fall apart or at least lose much of their weight upon deeper inspection.
Ultimately, I'm a not concerned about interactions between ApplicativeDo notation and fail.
Any automatic desugaring into 'fail' will be in a context which is necessarily incurring a monad constraint.
E.g.
do
Just x <- m
...
has to pick up the Monad constraint anyways to deal with the binding!
This leaves only code that does something like.
foo = x <*> fail y
which is hand written to invoke fail.
Given that the entire "tree" of the Applicative" is available for inspection and that that fail can't depend on any context internal to the Applicative and remain 'just Applicative' I have a hard time foreseeing any real applications lost by continuing to assume a context of:
class Monad m => MonadFail m
and there is a lot of value in the simple context.
Most of the value in ApplicativeDo notation comes from the opportunities for increased parallelism, not so much from the reduced constraints on the resulting code, and as we can see above, it'll never arise during the desguaring in a place that wouldn't incur a Monad constraint anyways.
Even getting rid of the Monad constraint w/ ApplicativeDo is going to require gymnastics around `return`.
-Edward
P.S. On an unrelated note, for the record, I'm very strongly +1 on a MonadFail instance for IO. There we use throwIO explicitly, so it is even able to be handled and caught locally. The set of things you can do in IO is large enough to support and reason about explicit failure.
P.P.S. I think if we extend the proposal to include an explicit member of the class for pattern match failure with the code we currently have lurking in the compiler for producing the string from the context, then most of the concerns raised by folks who would prefer to use a heavier weight -- but vastly harder to standardize -- exception mechanism would also be addressed in practice.
On Tue, Jun 16, 2015 at 11:07 AM, David Luposchainsky
We should clearly decide what "fail" is intended for - for programming errors or for exceptions.
What I see clashing with his point is backwards compatibility. Removing the `String` argument breaks all explicit invocations of `fail`. Unfortunately, we're not in a position to break very much. If someone has a better idea I'd love to hear about it though. ### ApplicativeDo ApplicativeDo is somewhere out there on the horizon, and we're not sure yet how much `fail` makes sense in the context of `Applicative`. An Applicative computation is statically determined in its shape, so it either always or never fails. Depending on previous results would introduce the `Monad` constraint anyway. Probing status - -------------- Henning has started to look at the impact of the proposal when explicit invocations of `fail` are considered as well, something I have not done in my original survey. Luckily, things don't look too bad, Lens and its forest of dependencies can be fixed in around ten trivial changes, for example. Greetings, David/quchen -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAEBAgAGBQJVgDvGAAoJELrQsaT5WQUspmIIAJi9UVYIitHv2CKvWSmk1fg0 hYaPRXDJMnyFS21v57+JeTPhM/dnI4k0guUUrlIB9k5WPaySQ6MKIAnB51o5O9Gv zt87FII5/oYsJtVPruKgBtLPbJVhg6zGUXmNco1S2wvB5m5HdBooQsiBRY+qiFfZ MJOdzXpRCrYJk/0PeF7sglBOElSwsSmGq/klvJUo4VeVAdi8bU+lKRfET/AmAAM5 oqckAI0SEaFo+w6EXBLPiL/F5SoFBmKR50Nu4NKWRBcoNGq7AwvWEKDZeU0PvC3a dykqSnFTRtL5LeWZnByuZTVVqlDG3afjX6ZYkrUbMKQeE9rVf24Gx9jlRusxSds= =zUDu -----END PGP SIGNATURE----- _______________________________________________ Libraries mailing list Libraries@haskell.orgmailto:Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries This email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please delete all copies and notify the sender immediately. You may wish to refer to the incorporation details of Standard Chartered PLC, Standard Chartered Bank and their subsidiaries at http://www.standardchartered.com/en/incorporation-details.html Insofar as this communication contains any market commentary, the market commentary has been prepared by a sales and/or trading desk of Standard Chartered Bank or its affiliate. It is not and does not constitute research material, independent research, recommendation or financial advice. Any market commentary is for information purpose only and shall not be relied for any other purpose, and is subject to the relevant disclaimers available at http://wholesalebanking.standardchartered.com/en/utility/Pages/d-mkt.aspx Please visit http://wholesalebanking.standardchartered.com/en/capabilities/financialmarke... for important information with respect to derivative products.

Hello, Are people actually using the string argument for anything else than throwing an error message into the user's face? (I've always seen Either String as a bit of a hack)? If not, I think it would be best to leave fail to errors (as in IO), and desugar failed pattern matches to mempty/empty instead. Best regards, Marcin Mrotek
participants (27)
-
Alexander Berntsen
-
Augustsson, Lennart
-
Bardur Arantsson
-
Bertram Felgenhauer
-
Brandon Allbery
-
Carter Schonwald
-
David Feuer
-
David Luposchainsky
-
Edward Kmett
-
Erik Hesselink
-
Evan Laforge
-
Felipe Lessa
-
Ganesh Sittampalam
-
Henning Thielemann
-
Herbert Valerio Riedel
-
Joachim Breitner
-
Johan Tibell
-
John Wiegley
-
Malcolm Wallace
-
Marcin Mrotek
-
Mario Blažević
-
Mario Blažević
-
Nikita Volkov
-
Roman Cheplyaka
-
Simon Peyton Jones
-
Tikhon Jelvis
-
Wolfgang Jeltsch