Monad of no `return` Proposal (MRP): Moving `return` out of `Monad`

Hello *, Concluding AMP and MFP, We (David and I) proudly present you the final installment of the Monad trilogy: Monad of no `return` Proposal ============================= TLDR: To complete the AMP, turn `Monad(return)` method into a top-level binding aliasing `Applicative(pure)`. Current Situation ----------------- With the implementation of Functor-Applicative-Monad Proposal (AMP)[1] and (at some point) the MonadFail proposal (MFP)[2] the AMP class hierarchy becomes class Functor f where fmap :: (a -> b) -> f a -> f b class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b (*>) :: f a -> f b -> f b u *> v = … (<*) :: f a -> f b -> f a u <* v = … class Applicative m => Monad m where (>>=) :: m a -> (a -> m b) -> m b return :: a -> m a return = pure (>>) :: m a -> m b -> m b m >> k = … class Monad m => MonadFail m where fail :: String -> m a Consequently, the `Monad` class is left with a now redundant `return` method as a historic artifact, as there's no compelling reason to have `pure` and `return` implemented differently. Traditionally, `return` is often used where `pure` would suffice today, forcing a `Monad` constraint even if a weaker `Applicative` would have sufficed. As a result, language extensions like `ApplicativeDo`[3] have to rewrite `return` to weaken its `Monad m =>` constraint to `Applicative m =>` in order to benefit existing code at the cost of introducing magic behavior at the type level. Finally, this redundancy becomes even more significant when viewed in light of the renewed Haskell standardisation process[7]: The next Haskell Report will almost certainly incorporate the AMP (and MFP) changes, and there's no justification for the Report to retain `return` as a method of `Monad`. A good reason would have been to retain backward compatibility with Haskell 2010. However, as the AMP superclass hierarchy requires `Monad` instances to be accompanied by `Applicative` instances (which aren't part of Haskell 2010, c.f. [6]), backward compatibility with Haskell 2010 goes out the window when it comes to defining `Monad` instances (unless via use of `-XCPP` or similar). Consequently, meeting the high bar for a formal document such as the Haskell Report demands that `Monad` shall not carry a redundant `return` method that serves no purpose anymore. Moreover, getting `return` out of the way is desirable to facilitate standardising potential candidates such as the earlier mentioned `ApplicativeDo` in the future and avoids the technical debt incurred by keeping around this language wart. Proposed Change --------------- Remove `return` as a method from the `Monad` class and in its place define a top-level binding with the weaker `Applicative` typeclass constraint: -- | Legacy alias for 'pure' return :: Applicative f => a -> f a return = pure This allows existing code using `return` to benefit from a weaker typeclass constraint as well as cleaning the `Monad` class from a redundant method in the post-AMP world. A possible migration strategy is described further below. Compatibility Considerations ---------------------------- Generalizing the type signature of a function from a `Monad` constraint to its superclass `Applicative` doesn't cause new type-errors in existing code. However, moving a method to a top-level binding obviously breaks code that assumes `return` to be a class method. Foremost, code that defines `Monad` instances it at risk: ### Instance Definitions Code defining `return` as part of an instance definition breaks. However, we had the foresight to provide a default implementation in `base-4.8` for `return` so that the following represents a proper minimal instance definition post-AMP: instance Functor Foo where fmap g foo = … instance Applicative Foo where pure x = … a1 <*> a2 = … instance Monad Foo where m >>= f = … -- NB: No mention of `return` Consequently, it is possible to write forward-compatible instances that are valid under this proposal starting with GHC 7.10/`base-4.8`. Heuristically `grep`ing through Hackage source-code reveals a non-negligible number of packages defining `Monad` instances with explicit `return` definitions[4]. This has a comparable impact to the AMP, and similarly will require a transition scheme aided by compiler warnings. ### Module Import/Export Specifications A second source of incompatibility may be due to `import`s. Specifically module import that assert `return` to be a method of `Monad`, e.g.: import Control.Monad (Monad ((>>=), return)) or import Prelude hiding (Monad(..)) import Control.Monad (Monad(..)) as Monad f = Monad.return () The dual situation can occur when re-exporting `return` via module export specifications. However, given that `return` is exported by `Prelude` and the examples above are rather artificial, we don't expect this to be a major source of breakage in the case of `return`. In fact, a heuristic grep[5] over Hackage source-code revealed only 21 packages affected. ### Example for writing compatible code instance Functor Foo where fmap g foo = … instance Applicative Foo where pure x = … a1 <*> a2 = … instance Monad Foo where m >>= f = … #if !(MIN_VERSION_base(4,8,0)) return = pure #endif Migration Strategy ------------------ The migration strategy is straightforward: **Phase 1** *(GHC 8.0)*: Implement new warning in GHC which gets triggered when `Monad` instances explicitly override the default `return` method implementation. **Phase 2** *(GHC 8.2 or later)*: When we're confident that the majority of Hackage has reacted to the warning (with the help of Stackage actively pursuing maintainers to update their packages) we turn the `return` method into a top-level binding and remove the warning implemented in Phase 1 from GHC again. Discussion period ----------------- A discussion period of three weeks (until 2015-10-15) should be enough to allow everyone to chime in as well as leave enough time to make the required preparations for GHC 8.0 should this proposal pass as we hope. ---- [1]: https://wiki.haskell.org/Functor-Applicative-Monad_Proposal [2]: https://wiki.haskell.org/MonadFail_Proposal [3]: https://ghc.haskell.org/trac/ghc/wiki/ApplicativeDo [4]: https://gist.github.com/hvr/b0e34463d85b58f169d9 [5]: https://gist.github.com/hvr/afcd040783d980594883 [6]: https://ghc.haskell.org/trac/ghc/ticket/9590 [7]: https://mail.haskell.org/pipermail/haskell-prime/2015-September/003936.html --

+1 on both the goal and the means of reaching it. That said, I suspect
the claim that "This has a comparable impact to the AMP" may be overly
optimistic. Many Monad instances were Applicative instances before
AMP, but I'd venture to guess that almost all Monad instances
currently define return explicitly.
On Thu, Sep 24, 2015 at 5:43 PM, Herbert Valerio Riedel
Hello *,
Concluding AMP and MFP, We (David and I) proudly present you the final installment of the Monad trilogy:
Monad of no `return` Proposal =============================
TLDR: To complete the AMP, turn `Monad(return)` method into a top-level binding aliasing `Applicative(pure)`.
Current Situation -----------------
With the implementation of Functor-Applicative-Monad Proposal (AMP)[1] and (at some point) the MonadFail proposal (MFP)[2] the AMP class hierarchy becomes
class Functor f where fmap :: (a -> b) -> f a -> f b
class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b u *> v = …
(<*) :: f a -> f b -> f a u <* v = …
class Applicative m => Monad m where (>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a return = pure
(>>) :: m a -> m b -> m b m >> k = …
class Monad m => MonadFail m where fail :: String -> m a
Consequently, the `Monad` class is left with a now redundant `return` method as a historic artifact, as there's no compelling reason to have `pure` and `return` implemented differently.
Traditionally, `return` is often used where `pure` would suffice today, forcing a `Monad` constraint even if a weaker `Applicative` would have sufficed.
As a result, language extensions like `ApplicativeDo`[3] have to rewrite `return` to weaken its `Monad m =>` constraint to `Applicative m =>` in order to benefit existing code at the cost of introducing magic behavior at the type level.
Finally, this redundancy becomes even more significant when viewed in light of the renewed Haskell standardisation process[7]: The next Haskell Report will almost certainly incorporate the AMP (and MFP) changes, and there's no justification for the Report to retain `return` as a method of `Monad`. A good reason would have been to retain backward compatibility with Haskell 2010. However, as the AMP superclass hierarchy requires `Monad` instances to be accompanied by `Applicative` instances (which aren't part of Haskell 2010, c.f. [6]), backward compatibility with Haskell 2010 goes out the window when it comes to defining `Monad` instances (unless via use of `-XCPP` or similar). Consequently, meeting the high bar for a formal document such as the Haskell Report demands that `Monad` shall not carry a redundant `return` method that serves no purpose anymore. Moreover, getting `return` out of the way is desirable to facilitate standardising potential candidates such as the earlier mentioned `ApplicativeDo` in the future and avoids the technical debt incurred by keeping around this language wart.
Proposed Change ---------------
Remove `return` as a method from the `Monad` class and in its place define a top-level binding with the weaker `Applicative` typeclass constraint:
-- | Legacy alias for 'pure' return :: Applicative f => a -> f a return = pure
This allows existing code using `return` to benefit from a weaker typeclass constraint as well as cleaning the `Monad` class from a redundant method in the post-AMP world.
A possible migration strategy is described further below.
Compatibility Considerations ----------------------------
Generalizing the type signature of a function from a `Monad` constraint to its superclass `Applicative` doesn't cause new type-errors in existing code.
However, moving a method to a top-level binding obviously breaks code that assumes `return` to be a class method. Foremost, code that defines `Monad` instances it at risk:
### Instance Definitions
Code defining `return` as part of an instance definition breaks. However, we had the foresight to provide a default implementation in `base-4.8` for `return` so that the following represents a proper minimal instance definition post-AMP:
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
-- NB: No mention of `return`
Consequently, it is possible to write forward-compatible instances that are valid under this proposal starting with GHC 7.10/`base-4.8`.
Heuristically `grep`ing through Hackage source-code reveals a non-negligible number of packages defining `Monad` instances with explicit `return` definitions[4]. This has a comparable impact to the AMP, and similarly will require a transition scheme aided by compiler warnings.
### Module Import/Export Specifications
A second source of incompatibility may be due to `import`s. Specifically module import that assert `return` to be a method of `Monad`, e.g.:
import Control.Monad (Monad ((>>=), return))
or
import Prelude hiding (Monad(..)) import Control.Monad (Monad(..)) as Monad
f = Monad.return ()
The dual situation can occur when re-exporting `return` via module export specifications.
However, given that `return` is exported by `Prelude` and the examples above are rather artificial, we don't expect this to be a major source of breakage in the case of `return`. In fact, a heuristic grep[5] over Hackage source-code revealed only 21 packages affected.
### Example for writing compatible code
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
#if !(MIN_VERSION_base(4,8,0)) return = pure #endif
Migration Strategy ------------------
The migration strategy is straightforward:
**Phase 1** *(GHC 8.0)*: Implement new warning in GHC which gets triggered when `Monad` instances explicitly override the default `return` method implementation.
**Phase 2** *(GHC 8.2 or later)*: When we're confident that the majority of Hackage has reacted to the warning (with the help of Stackage actively pursuing maintainers to update their packages) we turn the `return` method into a top-level binding and remove the warning implemented in Phase 1 from GHC again.
Discussion period -----------------
A discussion period of three weeks (until 2015-10-15) should be enough to allow everyone to chime in as well as leave enough time to make the required preparations for GHC 8.0 should this proposal pass as we hope.
----
[1]: https://wiki.haskell.org/Functor-Applicative-Monad_Proposal [2]: https://wiki.haskell.org/MonadFail_Proposal [3]: https://ghc.haskell.org/trac/ghc/wiki/ApplicativeDo [4]: https://gist.github.com/hvr/b0e34463d85b58f169d9 [5]: https://gist.github.com/hvr/afcd040783d980594883 [6]: https://ghc.haskell.org/trac/ghc/ticket/9590 [7]: https://mail.haskell.org/pipermail/haskell-prime/2015-September/003936.html
--
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

El 24 sept 2015, a las 18:02, David Feuer
escribió: +1 on both the goal and the means of reaching it. That said, I suspect the claim that "This has a comparable impact to the AMP" may be overly optimistic. Many Monad instances were Applicative instances before AMP, but I'd venture to guess that almost all Monad instances currently define return explicitly.
Right, I share this concern. This change breaks every package that defines a Monad (and comes close to turning every unmaintained package into a broken package. For what it's worth.). A couple questions: - Do you have any numbers (or grep heuristics) about the magnitude of breakage (esp. relative to AMP)? - What are the benefits of pulling "return" out instead of leaving it with the default "return = pure" and requiring the monad laws to hold? Is the rationale "since we're already willing to break things we shouldn't do half a job"? - Are there any (real-world) examples of people defining "pure" and "return" differently, e.g. for efficiency? - If we do decide to go forward with this, let's please get this in front of a wide audience asap! Tom
On Thu, Sep 24, 2015 at 5:43 PM, Herbert Valerio Riedel
wrote: Hello *, Concluding AMP and MFP, We (David and I) proudly present you the final installment of the Monad trilogy:
Monad of no `return` Proposal =============================
TLDR: To complete the AMP, turn `Monad(return)` method into a top-level binding aliasing `Applicative(pure)`.
Current Situation -----------------
With the implementation of Functor-Applicative-Monad Proposal (AMP)[1] and (at some point) the MonadFail proposal (MFP)[2] the AMP class hierarchy becomes
class Functor f where fmap :: (a -> b) -> f a -> f b
class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b u *> v = …
(<*) :: f a -> f b -> f a u <* v = …
class Applicative m => Monad m where (>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a return = pure
(>>) :: m a -> m b -> m b m >> k = …
class Monad m => MonadFail m where fail :: String -> m a
Consequently, the `Monad` class is left with a now redundant `return` method as a historic artifact, as there's no compelling reason to have `pure` and `return` implemented differently.
Traditionally, `return` is often used where `pure` would suffice today, forcing a `Monad` constraint even if a weaker `Applicative` would have sufficed.
As a result, language extensions like `ApplicativeDo`[3] have to rewrite `return` to weaken its `Monad m =>` constraint to `Applicative m =>` in order to benefit existing code at the cost of introducing magic behavior at the type level.
Finally, this redundancy becomes even more significant when viewed in light of the renewed Haskell standardisation process[7]: The next Haskell Report will almost certainly incorporate the AMP (and MFP) changes, and there's no justification for the Report to retain `return` as a method of `Monad`. A good reason would have been to retain backward compatibility with Haskell 2010. However, as the AMP superclass hierarchy requires `Monad` instances to be accompanied by `Applicative` instances (which aren't part of Haskell 2010, c.f. [6]), backward compatibility with Haskell 2010 goes out the window when it comes to defining `Monad` instances (unless via use of `-XCPP` or similar). Consequently, meeting the high bar for a formal document such as the Haskell Report demands that `Monad` shall not carry a redundant `return` method that serves no purpose anymore. Moreover, getting `return` out of the way is desirable to facilitate standardising potential candidates such as the earlier mentioned `ApplicativeDo` in the future and avoids the technical debt incurred by keeping around this language wart.
Proposed Change ---------------
Remove `return` as a method from the `Monad` class and in its place define a top-level binding with the weaker `Applicative` typeclass constraint:
-- | Legacy alias for 'pure' return :: Applicative f => a -> f a return = pure
This allows existing code using `return` to benefit from a weaker typeclass constraint as well as cleaning the `Monad` class from a redundant method in the post-AMP world.
A possible migration strategy is described further below.
Compatibility Considerations ----------------------------
Generalizing the type signature of a function from a `Monad` constraint to its superclass `Applicative` doesn't cause new type-errors in existing code.
However, moving a method to a top-level binding obviously breaks code that assumes `return` to be a class method. Foremost, code that defines `Monad` instances it at risk:
### Instance Definitions
Code defining `return` as part of an instance definition breaks. However, we had the foresight to provide a default implementation in `base-4.8` for `return` so that the following represents a proper minimal instance definition post-AMP:
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
-- NB: No mention of `return`
Consequently, it is possible to write forward-compatible instances that are valid under this proposal starting with GHC 7.10/`base-4.8`.
Heuristically `grep`ing through Hackage source-code reveals a non-negligible number of packages defining `Monad` instances with explicit `return` definitions[4]. This has a comparable impact to the AMP, and similarly will require a transition scheme aided by compiler warnings.
### Module Import/Export Specifications
A second source of incompatibility may be due to `import`s. Specifically module import that assert `return` to be a method of `Monad`, e.g.:
import Control.Monad (Monad ((>>=), return))
or
import Prelude hiding (Monad(..)) import Control.Monad (Monad(..)) as Monad
f = Monad.return ()
The dual situation can occur when re-exporting `return` via module export specifications.
However, given that `return` is exported by `Prelude` and the examples above are rather artificial, we don't expect this to be a major source of breakage in the case of `return`. In fact, a heuristic grep[5] over Hackage source-code revealed only 21 packages affected.
### Example for writing compatible code
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
#if !(MIN_VERSION_base(4,8,0)) return = pure #endif
Migration Strategy ------------------
The migration strategy is straightforward:
**Phase 1** *(GHC 8.0)*: Implement new warning in GHC which gets triggered when `Monad` instances explicitly override the default `return` method implementation.
**Phase 2** *(GHC 8.2 or later)*: When we're confident that the majority of Hackage has reacted to the warning (with the help of Stackage actively pursuing maintainers to update their packages) we turn the `return` method into a top-level binding and remove the warning implemented in Phase 1 from GHC again.
Discussion period -----------------
A discussion period of three weeks (until 2015-10-15) should be enough to allow everyone to chime in as well as leave enough time to make the required preparations for GHC 8.0 should this proposal pass as we hope.
----
[1]: https://wiki.haskell.org/Functor-Applicative-Monad_Proposal [2]: https://wiki.haskell.org/MonadFail_Proposal [3]: https://ghc.haskell.org/trac/ghc/wiki/ApplicativeDo [4]: https://gist.github.com/hvr/b0e34463d85b58f169d9 [5]: https://gist.github.com/hvr/afcd040783d980594883 [6]: https://ghc.haskell.org/trac/ghc/ticket/9590 [7]: https://mail.haskell.org/pipermail/haskell-prime/2015-September/003936.html
--
_______________________________________________ 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

David Feuer wrote:
+1 on both the goal and the means of reaching it. That said, I suspect the claim that "This has a comparable impact to the AMP" may be overly optimistic.
I want to echo this concern. In fact, the most common way of fixing code after the AMP proposal seems to have been to mechanically add instances instance Functor Foo where fmap = liftM instance Applicative Foo where pure = return (<*>) = ap whenever the compiler complained about a missing Applicative instance for a monad Foo. All those Applicative instances would have to be rewritten under the MRP proposal, and that task is not purely mechanical, since it involves moving existing code, so I'd say that the burden would be higher than after the AMP proposal. How many of those Applicative instances are there in hackage? Cheers, Bertram

What about the derived functions in Control.Monad, such as liftM? Shall we
similarly relax their constraints to Applicative and consider them
"legacy"? (Did this already happen when I wasn't looking?)
On Thursday, September 24, 2015, John Wiegley
Herbert Valerio Riedel
javascript:;> writes: TLDR: To complete the AMP, turn `Monad(return)` method into a top-level binding aliasing `Applicative(pure)`.
Very much +1.
John _______________________________________________ Libraries mailing list Libraries@haskell.org javascript:; http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
-- -- Dan Burton

Sadly liftM vs. liftA actually retains a useful distinction, one is a
definition of fmap in terms of (>>=) and the other in terms of (<*>).
`ap` gives a default definition of (<*>) in terms of (>>=), but if someone
instead writes (<*>) = liftM2 id today, then erasing the distinction would
turn that into a circular definition, transforming obviously-correct
existant code silently into a _|_.
-Edward
On Thu, Sep 24, 2015 at 8:36 PM, Dan Burton
What about the derived functions in Control.Monad, such as liftM? Shall we similarly relax their constraints to Applicative and consider them "legacy"? (Did this already happen when I wasn't looking?)
On Thursday, September 24, 2015, John Wiegley
wrote: > Herbert Valerio Riedel
writes: TLDR: To complete the AMP, turn `Monad(return)` method into a top-level binding aliasing `Applicative(pure)`.
Very much +1.
John _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
-- -- Dan Burton
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

A conditional +1 from me, the condition being to allow the same monad instance code to compile at least with GHC versions 7.8, 7.10, and 8.0 without any CPP directives. I think that can be accomplished by an extra clarification that the meaning of "override" in
**Phase 1** *(GHC 8.0)*: Implement new warning in GHC which gets triggered when `Monad` instances explicitly override the default `return` method implementation.
does *not* include a re-definition of return = pure Yes, I realize this corner case would be a wart in the next language standard. We could fix that by disabling even this re-definition in case {#- LANGUAGE Haskell2020 #-} or equivalent is declared. Perhaps there should be two pragmas, {#- LANGUAGE Haskell2020+ #-} and {#- LANGUAGE Haskell2010-2020 #-}?

I'm a rather enthusiastic +1 on this, given a sufficiently long time table
for the switch!
We ARE asking a lot of people to break code here.
It does drastically reduce the amount of "magic" involved in the
ApplicativeDo story and avoids enshrining the current historical artifact
in a future Haskell report that includes the AMP.
I'd also like to consider employing the exact same migration plan for (>>)
at the same time. It is redundant with (*>), and the choice of which gets
implemented in terms of the other introduces precisely the same set of
issues. If we can do that then this would fix the remaining performance
issues for mapM, letting us eventually remove that from Traversable as
well, moving it to a top level alias in the same way -- maybe not until 8.8
or something, but it'd at least give us a roadmap to get there eventually.
-Edward
On Thu, Sep 24, 2015 at 5:43 PM, Herbert Valerio Riedel
Hello *,
Concluding AMP and MFP, We (David and I) proudly present you the final installment of the Monad trilogy:
Monad of no `return` Proposal =============================
TLDR: To complete the AMP, turn `Monad(return)` method into a top-level binding aliasing `Applicative(pure)`.
Current Situation -----------------
With the implementation of Functor-Applicative-Monad Proposal (AMP)[1] and (at some point) the MonadFail proposal (MFP)[2] the AMP class hierarchy becomes
class Functor f where fmap :: (a -> b) -> f a -> f b
class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b u *> v = …
(<*) :: f a -> f b -> f a u <* v = …
class Applicative m => Monad m where (>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a return = pure
(>>) :: m a -> m b -> m b m >> k = …
class Monad m => MonadFail m where fail :: String -> m a
Consequently, the `Monad` class is left with a now redundant `return` method as a historic artifact, as there's no compelling reason to have `pure` and `return` implemented differently.
Traditionally, `return` is often used where `pure` would suffice today, forcing a `Monad` constraint even if a weaker `Applicative` would have sufficed.
As a result, language extensions like `ApplicativeDo`[3] have to rewrite `return` to weaken its `Monad m =>` constraint to `Applicative m =>` in order to benefit existing code at the cost of introducing magic behavior at the type level.
Finally, this redundancy becomes even more significant when viewed in light of the renewed Haskell standardisation process[7]: The next Haskell Report will almost certainly incorporate the AMP (and MFP) changes, and there's no justification for the Report to retain `return` as a method of `Monad`. A good reason would have been to retain backward compatibility with Haskell 2010. However, as the AMP superclass hierarchy requires `Monad` instances to be accompanied by `Applicative` instances (which aren't part of Haskell 2010, c.f. [6]), backward compatibility with Haskell 2010 goes out the window when it comes to defining `Monad` instances (unless via use of `-XCPP` or similar). Consequently, meeting the high bar for a formal document such as the Haskell Report demands that `Monad` shall not carry a redundant `return` method that serves no purpose anymore. Moreover, getting `return` out of the way is desirable to facilitate standardising potential candidates such as the earlier mentioned `ApplicativeDo` in the future and avoids the technical debt incurred by keeping around this language wart.
Proposed Change ---------------
Remove `return` as a method from the `Monad` class and in its place define a top-level binding with the weaker `Applicative` typeclass constraint:
-- | Legacy alias for 'pure' return :: Applicative f => a -> f a return = pure
This allows existing code using `return` to benefit from a weaker typeclass constraint as well as cleaning the `Monad` class from a redundant method in the post-AMP world.
A possible migration strategy is described further below.
Compatibility Considerations ----------------------------
Generalizing the type signature of a function from a `Monad` constraint to its superclass `Applicative` doesn't cause new type-errors in existing code.
However, moving a method to a top-level binding obviously breaks code that assumes `return` to be a class method. Foremost, code that defines `Monad` instances it at risk:
### Instance Definitions
Code defining `return` as part of an instance definition breaks. However, we had the foresight to provide a default implementation in `base-4.8` for `return` so that the following represents a proper minimal instance definition post-AMP:
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
-- NB: No mention of `return`
Consequently, it is possible to write forward-compatible instances that are valid under this proposal starting with GHC 7.10/`base-4.8`.
Heuristically `grep`ing through Hackage source-code reveals a non-negligible number of packages defining `Monad` instances with explicit `return` definitions[4]. This has a comparable impact to the AMP, and similarly will require a transition scheme aided by compiler warnings.
### Module Import/Export Specifications
A second source of incompatibility may be due to `import`s. Specifically module import that assert `return` to be a method of `Monad`, e.g.:
import Control.Monad (Monad ((>>=), return))
or
import Prelude hiding (Monad(..)) import Control.Monad (Monad(..)) as Monad
f = Monad.return ()
The dual situation can occur when re-exporting `return` via module export specifications.
However, given that `return` is exported by `Prelude` and the examples above are rather artificial, we don't expect this to be a major source of breakage in the case of `return`. In fact, a heuristic grep[5] over Hackage source-code revealed only 21 packages affected.
### Example for writing compatible code
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
#if !(MIN_VERSION_base(4,8,0)) return = pure #endif
Migration Strategy ------------------
The migration strategy is straightforward:
**Phase 1** *(GHC 8.0)*: Implement new warning in GHC which gets triggered when `Monad` instances explicitly override the default `return` method implementation.
**Phase 2** *(GHC 8.2 or later)*: When we're confident that the majority of Hackage has reacted to the warning (with the help of Stackage actively pursuing maintainers to update their packages) we turn the `return` method into a top-level binding and remove the warning implemented in Phase 1 from GHC again.
Discussion period -----------------
A discussion period of three weeks (until 2015-10-15) should be enough to allow everyone to chime in as well as leave enough time to make the required preparations for GHC 8.0 should this proposal pass as we hope.
----
[1]: https://wiki.haskell.org/Functor-Applicative-Monad_Proposal [2]: https://wiki.haskell.org/MonadFail_Proposal [3]: https://ghc.haskell.org/trac/ghc/wiki/ApplicativeDo [4]: https://gist.github.com/hvr/b0e34463d85b58f169d9 [5]: https://gist.github.com/hvr/afcd040783d980594883 [6]: https://ghc.haskell.org/trac/ghc/ticket/9590 [7]: https://mail.haskell.org/pipermail/haskell-prime/2015-September/003936.html
--
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Yes, and I think there are still some more overly-specific things that come
in here too, such as replicateM and filterM, which I don't think have been
generalized yet.
On Sep 24, 2015 10:40 PM, "Edward Kmett"
I'm a rather enthusiastic +1 on this, given a sufficiently long time table for the switch!
We ARE asking a lot of people to break code here.
It does drastically reduce the amount of "magic" involved in the ApplicativeDo story and avoids enshrining the current historical artifact in a future Haskell report that includes the AMP.
I'd also like to consider employing the exact same migration plan for (>>) at the same time. It is redundant with (*>), and the choice of which gets implemented in terms of the other introduces precisely the same set of issues. If we can do that then this would fix the remaining performance issues for mapM, letting us eventually remove that from Traversable as well, moving it to a top level alias in the same way -- maybe not until 8.8 or something, but it'd at least give us a roadmap to get there eventually.
-Edward
On Thu, Sep 24, 2015 at 5:43 PM, Herbert Valerio Riedel
wrote: Hello *,
Concluding AMP and MFP, We (David and I) proudly present you the final installment of the Monad trilogy:
Monad of no `return` Proposal =============================
TLDR: To complete the AMP, turn `Monad(return)` method into a top-level binding aliasing `Applicative(pure)`.
Current Situation -----------------
With the implementation of Functor-Applicative-Monad Proposal (AMP)[1] and (at some point) the MonadFail proposal (MFP)[2] the AMP class hierarchy becomes
class Functor f where fmap :: (a -> b) -> f a -> f b
class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b u *> v = …
(<*) :: f a -> f b -> f a u <* v = …
class Applicative m => Monad m where (>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a return = pure
(>>) :: m a -> m b -> m b m >> k = …
class Monad m => MonadFail m where fail :: String -> m a
Consequently, the `Monad` class is left with a now redundant `return` method as a historic artifact, as there's no compelling reason to have `pure` and `return` implemented differently.
Traditionally, `return` is often used where `pure` would suffice today, forcing a `Monad` constraint even if a weaker `Applicative` would have sufficed.
As a result, language extensions like `ApplicativeDo`[3] have to rewrite `return` to weaken its `Monad m =>` constraint to `Applicative m =>` in order to benefit existing code at the cost of introducing magic behavior at the type level.
Finally, this redundancy becomes even more significant when viewed in light of the renewed Haskell standardisation process[7]: The next Haskell Report will almost certainly incorporate the AMP (and MFP) changes, and there's no justification for the Report to retain `return` as a method of `Monad`. A good reason would have been to retain backward compatibility with Haskell 2010. However, as the AMP superclass hierarchy requires `Monad` instances to be accompanied by `Applicative` instances (which aren't part of Haskell 2010, c.f. [6]), backward compatibility with Haskell 2010 goes out the window when it comes to defining `Monad` instances (unless via use of `-XCPP` or similar). Consequently, meeting the high bar for a formal document such as the Haskell Report demands that `Monad` shall not carry a redundant `return` method that serves no purpose anymore. Moreover, getting `return` out of the way is desirable to facilitate standardising potential candidates such as the earlier mentioned `ApplicativeDo` in the future and avoids the technical debt incurred by keeping around this language wart.
Proposed Change ---------------
Remove `return` as a method from the `Monad` class and in its place define a top-level binding with the weaker `Applicative` typeclass constraint:
-- | Legacy alias for 'pure' return :: Applicative f => a -> f a return = pure
This allows existing code using `return` to benefit from a weaker typeclass constraint as well as cleaning the `Monad` class from a redundant method in the post-AMP world.
A possible migration strategy is described further below.
Compatibility Considerations ----------------------------
Generalizing the type signature of a function from a `Monad` constraint to its superclass `Applicative` doesn't cause new type-errors in existing code.
However, moving a method to a top-level binding obviously breaks code that assumes `return` to be a class method. Foremost, code that defines `Monad` instances it at risk:
### Instance Definitions
Code defining `return` as part of an instance definition breaks. However, we had the foresight to provide a default implementation in `base-4.8` for `return` so that the following represents a proper minimal instance definition post-AMP:
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
-- NB: No mention of `return`
Consequently, it is possible to write forward-compatible instances that are valid under this proposal starting with GHC 7.10/`base-4.8`.
Heuristically `grep`ing through Hackage source-code reveals a non-negligible number of packages defining `Monad` instances with explicit `return` definitions[4]. This has a comparable impact to the AMP, and similarly will require a transition scheme aided by compiler warnings.
### Module Import/Export Specifications
A second source of incompatibility may be due to `import`s. Specifically module import that assert `return` to be a method of `Monad`, e.g.:
import Control.Monad (Monad ((>>=), return))
or
import Prelude hiding (Monad(..)) import Control.Monad (Monad(..)) as Monad
f = Monad.return ()
The dual situation can occur when re-exporting `return` via module export specifications.
However, given that `return` is exported by `Prelude` and the examples above are rather artificial, we don't expect this to be a major source of breakage in the case of `return`. In fact, a heuristic grep[5] over Hackage source-code revealed only 21 packages affected.
### Example for writing compatible code
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
#if !(MIN_VERSION_base(4,8,0)) return = pure #endif
Migration Strategy ------------------
The migration strategy is straightforward:
**Phase 1** *(GHC 8.0)*: Implement new warning in GHC which gets triggered when `Monad` instances explicitly override the default `return` method implementation.
**Phase 2** *(GHC 8.2 or later)*: When we're confident that the majority of Hackage has reacted to the warning (with the help of Stackage actively pursuing maintainers to update their packages) we turn the `return` method into a top-level binding and remove the warning implemented in Phase 1 from GHC again.
Discussion period -----------------
A discussion period of three weeks (until 2015-10-15) should be enough to allow everyone to chime in as well as leave enough time to make the required preparations for GHC 8.0 should this proposal pass as we hope.
----
[1]: https://wiki.haskell.org/Functor-Applicative-Monad_Proposal [2]: https://wiki.haskell.org/MonadFail_Proposal [3]: https://ghc.haskell.org/trac/ghc/wiki/ApplicativeDo [4]: https://gist.github.com/hvr/b0e34463d85b58f169d9 [5]: https://gist.github.com/hvr/afcd040783d980594883 [6]: https://ghc.haskell.org/trac/ghc/ticket/9590 [7]: https://mail.haskell.org/pipermail/haskell-prime/2015-September/003936.html
--
_______________________________________________ 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 24/09/2015, David Feuer
Yes, and I think there are still some more overly-specific things that come in here too, such as replicateM and filterM, which I don't think have been generalized yet.
Someone posted a patch for that... https://ghc.haskell.org/trac/ghc/ticket/10168

On 25.09.2015 04:40, Edward Kmett wrote:
I'd also like to consider employing the exact same migration plan for (>>) at the same time. It is redundant with (*>), and the choice of which gets implemented in terms of the other introduces precisely the same set of issues. If we can do that then this would fix the remaining performance issues for mapM, letting us eventually remove that from Traversable as well, moving it to a top level alias in the same way -- maybe not until 8.8 or something, but it'd at least give us a roadmap to get there eventually.
+1 on bundling these changes.
On Thu, Sep 24, 2015 at 5:43 PM, Herbert Valerio Riedel
mailto:hvr@gnu.org> wrote: Hello *,
Concluding AMP and MFP, We (David and I) proudly present you the final installment of the Monad trilogy:
Monad of no `return` Proposal =============================
TLDR: To complete the AMP, turn `Monad(return)` method into a top-level binding aliasing `Applicative(pure)`.
Current Situation -----------------
With the implementation of Functor-Applicative-Monad Proposal (AMP)[1] and (at some point) the MonadFail proposal (MFP)[2] the AMP class hierarchy becomes
class Functor f where fmap :: (a -> b) -> f a -> f b
class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b u *> v = …
(<*) :: f a -> f b -> f a u <* v = …
class Applicative m => Monad m where (>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a return = pure
(>>) :: m a -> m b -> m b m >> k = …
class Monad m => MonadFail m where fail :: String -> m a
Consequently, the `Monad` class is left with a now redundant `return` method as a historic artifact, as there's no compelling reason to have `pure` and `return` implemented differently.
Traditionally, `return` is often used where `pure` would suffice today, forcing a `Monad` constraint even if a weaker `Applicative` would have sufficed.
As a result, language extensions like `ApplicativeDo`[3] have to rewrite `return` to weaken its `Monad m =>` constraint to `Applicative m =>` in order to benefit existing code at the cost of introducing magic behavior at the type level.
Finally, this redundancy becomes even more significant when viewed in light of the renewed Haskell standardisation process[7]: The next Haskell Report will almost certainly incorporate the AMP (and MFP) changes, and there's no justification for the Report to retain `return` as a method of `Monad`. A good reason would have been to retain backward compatibility with Haskell 2010. However, as the AMP superclass hierarchy requires `Monad` instances to be accompanied by `Applicative` instances (which aren't part of Haskell 2010, c.f. [6]), backward compatibility with Haskell 2010 goes out the window when it comes to defining `Monad` instances (unless via use of `-XCPP` or similar). Consequently, meeting the high bar for a formal document such as the Haskell Report demands that `Monad` shall not carry a redundant `return` method that serves no purpose anymore. Moreover, getting `return` out of the way is desirable to facilitate standardising potential candidates such as the earlier mentioned `ApplicativeDo` in the future and avoids the technical debt incurred by keeping around this language wart.
Proposed Change ---------------
Remove `return` as a method from the `Monad` class and in its place define a top-level binding with the weaker `Applicative` typeclass constraint:
-- | Legacy alias for 'pure' return :: Applicative f => a -> f a return = pure
This allows existing code using `return` to benefit from a weaker typeclass constraint as well as cleaning the `Monad` class from a redundant method in the post-AMP world.
A possible migration strategy is described further below.
Compatibility Considerations ----------------------------
Generalizing the type signature of a function from a `Monad` constraint to its superclass `Applicative` doesn't cause new type-errors in existing code.
However, moving a method to a top-level binding obviously breaks code that assumes `return` to be a class method. Foremost, code that defines `Monad` instances it at risk:
### Instance Definitions
Code defining `return` as part of an instance definition breaks. However, we had the foresight to provide a default implementation in `base-4.8` for `return` so that the following represents a proper minimal instance definition post-AMP:
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
-- NB: No mention of `return`
Consequently, it is possible to write forward-compatible instances that are valid under this proposal starting with GHC 7.10/`base-4.8`.
Heuristically `grep`ing through Hackage source-code reveals a non-negligible number of packages defining `Monad` instances with explicit `return` definitions[4]. This has a comparable impact to the AMP, and similarly will require a transition scheme aided by compiler warnings.
### Module Import/Export Specifications
A second source of incompatibility may be due to `import`s. Specifically module import that assert `return` to be a method of `Monad`, e.g.:
import Control.Monad (Monad ((>>=), return))
or
import Prelude hiding (Monad(..)) import Control.Monad (Monad(..)) as Monad
f = Monad.return ()
The dual situation can occur when re-exporting `return` via module export specifications.
However, given that `return` is exported by `Prelude` and the examples above are rather artificial, we don't expect this to be a major source of breakage in the case of `return`. In fact, a heuristic grep[5] over Hackage source-code revealed only 21 packages affected.
### Example for writing compatible code
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
#if !(MIN_VERSION_base(4,8,0)) return = pure #endif
Migration Strategy ------------------
The migration strategy is straightforward:
**Phase 1** *(GHC 8.0)*: Implement new warning in GHC which gets triggered when `Monad` instances explicitly override the default `return` method implementation.
**Phase 2** *(GHC 8.2 or later)*: When we're confident that the majority of Hackage has reacted to the warning (with the help of Stackage actively pursuing maintainers to update their packages) we turn the `return` method into a top-level binding and remove the warning implemented in Phase 1 from GHC again.
Discussion period -----------------
A discussion period of three weeks (until 2015-10-15) should be enough to allow everyone to chime in as well as leave enough time to make the required preparations for GHC 8.0 should this proposal pass as we hope.
----
[1]: https://wiki.haskell.org/Functor-Applicative-Monad_Proposal [2]: https://wiki.haskell.org/MonadFail_Proposal [3]: https://ghc.haskell.org/trac/ghc/wiki/ApplicativeDo [4]: https://gist.github.com/hvr/b0e34463d85b58f169d9 [5]: https://gist.github.com/hvr/afcd040783d980594883 [6]: https://ghc.haskell.org/trac/ghc/ticket/9590 [7]: https://mail.haskell.org/pipermail/haskell-prime/2015-September/003936.html
--
_______________________________________________ Libraries mailing list Libraries@haskell.org mailto: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
-- Andreas Abel <>< Du bist der geliebte Mensch. Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden andreas.abel@gu.se http://www2.tcs.ifi.lmu.de/~abel/

On 2015-09-25 at 04:40:25 +0200, Edward Kmett wrote:
I'm a rather enthusiastic +1 on this, given a sufficiently long time table for the switch!
We ARE asking a lot of people to break code here.
It does drastically reduce the amount of "magic" involved in the ApplicativeDo story and avoids enshrining the current historical artifact in a future Haskell report that includes the AMP.
I'd also like to consider employing the exact same migration plan for (>>) at the same time. It is redundant with (*>), and the choice of which gets implemented in terms of the other introduces precisely the same set of issues. If we can do that then this would fix the remaining performance issues for mapM, letting us eventually remove that from Traversable as well, moving it to a top level alias in the same way -- maybe not until 8.8 or something, but it'd at least give us a roadmap to get there eventually.
+1 It makes totally sense to apply the same treatment for `Monad((>>))` also because the same warning machinery in GHC can be reused for that. A simple grep heuristic shows about 114 packages affected: https://gist.github.com/hvr/0dd477935266c00c58e0

On 09/24/2015 11:43 PM, Herbert Valerio Riedel wrote:
Hello *,
+1, just a minor... nitpick, I guess:
-- | Legacy alias for 'pure' return :: Applicative f => a -> f a return = pure
I propse to remove the "Legacy" designation (see below for reasoning). There should probably also be some reference to the Applicative type class, so I'd propose a wording more like: Alias for 'pure' in the 'Applicative' type class. Reasoning: I happen to rather like "return" for purely pedagogical purposes since it lets you pretend (as a sufficient-for-beginners approximation) that code in the do-notation in IO is imperative code and "return" is the usual name for what it does in that context. I think that has a certain value, but "Legacy" is quite off-putting. Presumably we aren't talking about removing "return" itself any time in the next, say, 5-10 years...? (That _would_ break a hell of a lot of code.) Anyway, just a (very) minor nitpick to consider.
However, given that `return` is exported by `Prelude` and the examples above are rather artificial, we don't expect this to be a major source of breakage in the case of `return`. In fact, a heuristic grep[5] over Hackage source-code revealed only 21 packages affected.
How many reverse dependencies do those packages have? (I.e. how many packages are going to require at least a version bump.) Regards,

I propse to remove the "Legacy" designation (see below for reasoning). There should probably also be some reference to the Applicative type class, so I'd propose a wording more like:
Alias for 'pure' in the 'Applicative' type class.
Reasoning: I happen to rather like "return" for purely pedagogical purposes since it lets you pretend (as a sufficient-for-beginners approximation) that code in the do-notation in IO is imperative code and "return" is the usual name for what it does in that context. I think that has a certain value, but "Legacy" is quite off-putting.
+1 "Legacy" suggests that there is a plan to remove `return` at some point. -- Michael Walker (http://www.barrucadu.co.uk)

On Fri, Sep 25, 2015 at 1:23 AM, Bardur Arantsson
Reasoning: I happen to rather like "return" for purely pedagogical purposes since it lets you pretend (as a sufficient-for-beginners approximation) that code in the do-notation in IO is imperative code and "return" is the usual name for what it does in that context. I think that has a certain value, but "Legacy" is quite off-putting.
+1. I like the proposal to merge pure/return into a single thing, but I rather prefer the name "return" for all the same pedagogical reasons it was originally chosen. -- Live well, ~wren

Agreed.
The name pure is pretty awful. It's not _that_ big of a deal, but pure is
annoyingly senseless and my coauthor noticed this of her own accord as well.
+1 for the proposal, just wish it wasn't named pure ;)
On Fri, Sep 25, 2015 at 6:47 PM, wren romano
On Fri, Sep 25, 2015 at 1:23 AM, Bardur Arantsson
wrote: Reasoning: I happen to rather like "return" for purely pedagogical purposes since it lets you pretend (as a sufficient-for-beginners approximation) that code in the do-notation in IO is imperative code and "return" is the usual name for what it does in that context. I think that has a certain value, but "Legacy" is quite off-putting.
+1.
I like the proposal to merge pure/return into a single thing, but I rather prefer the name "return" for all the same pedagogical reasons it was originally chosen.
-- Live well, ~wren _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
-- Chris Allen Currently working on http://haskellbook.com

I think they're both wretched. return makes beginners think it's a control
structure; pure just seems meaningless (I guess that's a slight
improvement, arguably). I'd have gone for something like inject myself, but
there's no way that's happening.
On Sep 25, 2015 8:00 PM, "Christopher Allen"
Agreed.
The name pure is pretty awful. It's not _that_ big of a deal, but pure is annoyingly senseless and my coauthor noticed this of her own accord as well.
+1 for the proposal, just wish it wasn't named pure ;)
On Fri, Sep 25, 2015 at 6:47 PM, wren romano
wrote: On Fri, Sep 25, 2015 at 1:23 AM, Bardur Arantsson
wrote: Reasoning: I happen to rather like "return" for purely pedagogical purposes since it lets you pretend (as a sufficient-for-beginners approximation) that code in the do-notation in IO is imperative code and "return" is the usual name for what it does in that context. I think that has a certain value, but "Legacy" is quite off-putting.
+1.
I like the proposal to merge pure/return into a single thing, but I rather prefer the name "return" for all the same pedagogical reasons it was originally chosen.
-- Live well, ~wren _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
-- Chris Allen Currently working on http://haskellbook.com
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

On Fri, Sep 25, 2015 at 7:56 PM, David Feuer
I think they're both wretched. return makes beginners think it's a control structure; pure just seems meaningless (I guess that's a slight improvement, arguably). I'd have gone for something like inject myself, but there's no way that's happening.
Just my $0.02: I wouldn't say `pure` is meaningless. It takes a value and turns it into a computation in the relevant computational context that performs no effects apart from yielding the given value. Computations whose only effect is yielding a single value are typically said to be pure computations in the Haskell community. It's a really nice name. `return`, on the other hand, is tremendously misleading for imperative programmers who won't understand why in the world anything after it isn't dead code. It'd be a reasonable name for a continuation monad action that actually did something akin to what it does in the contexts whence the name was borrowed, but even that would be inaccurate since not even in the context of a continuation monad is there a notion of "the current procedure". In any case, `return` evokes the imperative intuition in learners that should be trying desperately to avoid the imperative intuition in order to understand Haskell's use of the word "function", especially since the Haskell community does also use the word "return" to talk about the value produced by a function when applied to an argument. I see no pedagogical value in `return`, and I've had better results teaching Haskell when I avoid mentioning it at all. Not a single Haskell monad can be described clearly and accurately using the traditional vocabulary of imperative programming; not even IO.

Box is good but overlaps with unboxed/boxed types. Wrap is good.
On Fri, Sep 25, 2015 at 7:27 PM, Imants Cekusins
wish it wasn't named pure
How about "wrap" or "box" (as in box-unbox)?
-- Chris Allen Currently working on http://haskellbook.com

unmonadify
On Fri, Sep 25, 2015 at 10:25 PM M Farkas-Dyck
On 25/09/2015, Reid Barton
wrote: We're not actually proposing names. Thanks.
I'm not arguing to rename it now, but some were proposing names, for examples: inject, box, wrap. _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

A rename of neither pure nor return is going to happen. - There is no known better name - Renaming a popular class function eclipses any breaking change in its headache potential (since the changes implied are highly non-local) - Adding the name as a top-level synonym aliasing return aliasing return would just grow the zoo of synonyms that we're trying to get rid of Can we end the bikeshedding, or move this to a different discussion on the list? Greetings, David/quchen

On 25 Sep 2015, at 20:47 , wren romano
wrote: On Fri, Sep 25, 2015 at 1:23 AM, Bardur Arantsson
wrote: Reasoning: I happen to rather like "return" for purely pedagogical purposes since it lets you pretend (as a sufficient-for-beginners approximation) that code in the do-notation in IO is imperative code and "return" is the usual name for what it does in that context.
Like in do a <- return 5 b <- return 3 return (a+b) I think that calling pure return was a big mistake from the very beginning, Doaitse
I think that has a certain value, but "Legacy" is quite off-putting.
+1.
I like the proposal to merge pure/return into a single thing, but I rather prefer the name "return" for all the same pedagogical reasons it was originally chosen.
-- Live well, ~wren _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Hi, At least with the current situation, it is possible (from my experience so far, but I don't claim to have tested extensively) to write code that works both with the old class hierarchy as well as the new: * Add an import Control.Applicative * Add an explicit method definition "return = pure" for Monad instances * Add Applicative to contexts in a few strategic places. That's a big plus in my books for people who for one reason or another would like to write code that works against an as broad range of different versions of the available Haskell tools as possible. On the other hand, I don't really understand the rationale:
Traditionally, `return` is often used where `pure` would suffice today, forcing a `Monad` constraint even if a weaker `Applicative` would have sufficed.
As a result, language extensions like `ApplicativeDo`[3] have to rewrite `return` to weaken its `Monad m =>` constraint to `Applicative m =>` in order to benefit existing code at the cost of introducing magic behavior at the type level.
If code is genuinely applicative, why not encourage this to be clearly signalled by use of "pure" instead of "return"? Surely that would benefit long-term readability a lot more than supporting use of the "wrong" function. And as ApplicativeDo is a new extension, removing the magic so as to force such a change for code that really is applicative ought not to cause that much trouble for existing code. Thus, encourage (or force) people to say what they mean by using "pure" and "return" appropriately. I'm thus (very) unconvinced about the merits of this proposal. Best, /Henrik -- Henrik Nilsson School of Computer Science The University of Nottingham nhn@cs.nott.ac.uk This message and any attachment are intended solely for the addressee and may contain confidential information. If you have received this message in error, please send it back to me, and immediately delete it. Please do not use, copy or disclose the information contained in this message or in any attachment. Any views or opinions expressed by the author of this email do not necessarily reflect the views of the University of Nottingham. This message has been checked for viruses but the contents of an attachment may still contain software viruses which could damage your computer system, you are advised to perform your own checks. Email communications with the University of Nottingham may be monitored as permitted by UK legislation.

On 09/25/2015 01:14 PM, Vincent Hanquez wrote:
On 24/09/2015 22:43, Herbert Valerio Riedel wrote:
Hello *,
Concluding AMP and MFP, We (David and I) proudly present you the final installment of the Monad trilogy:
Very much +1, despite all the compat annoyances this is going to bring.
Ditto.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 Enthusiastic +1 from me too, of course. - -- Alexander alexander@plaimi.net https://secure.plaimi.net/~alexander -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAEBCgAGBQJWBTfiAAoJENQqWdRUGk8BU00QAMQfZo07CKomsjqcwNCDNqdm ifIhiz2kldR+A/gp6t/8IRf0RG3ZgZfwxhR5s/BWt7yV28napZfTMHPTfV8gE+bm V8AzvsXe/XLa9gTDyxqnY+ovYBDnEqmbX3SU03rRdtcN3jHiNuFkfIEIkRx6+HVx BKfoebxD7r1tgs/4nxjD8HljJEh6W8ux2Q8+sMWiCJEbVN5ixzTzGSk28vT2Ldyl GkoZJoXYM4K3WVCn23UmH9eokbdbnaCu2WRqzGgM7eQf+qqpouSjE3KRL5d9O/pE NMJIrNkC1L613GpfNeHLikOCKd78vbT0xnXyKHwAxv4Cr/7IZI3dyu+5MYwFntrY cdX7PgNQw7RN/tvZ63OOaRQEqvQfiOSdhPdFxAF5MabPNYMZMjIHqJuQseBaiUJf SWOU9oYNWW7XQVaQRVS5bP0KvRUhsA2+QXEd6pnhBEZ6u7qRQhaJowjca/A1TbB/ LHVG9nXE04fvc+CRkMK/xZEbuNWiMF0p4CZUiyeuAzhcZ9dge367ExfrTpTSLz8O Gfh04LgWs3rnvc3w8yhJJjcfsHhYZKQJMv40Rn8dgE/hyGFRpwQvBvFolZtFBZiS h6A/MyLDaSJCw3jwj+cU5PGLULGzdfNnTRlJ/jb4/CD2xUEOaQcAd+NvIJOlREcK RZBk4o5MU1aCsujOzjRd =VfnC -----END PGP SIGNATURE-----

Is the upgrade automatable with tooling that analyzes Haskell source code?
If so can we provide an executable that will automatically upgrade packages?
Pull requests could even be sent automatically.
On Fri, Sep 25, 2015 at 5:02 AM, Alexander Berntsen
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512
Enthusiastic +1 from me too, of course.
- -- Alexander alexander@plaimi.net https://secure.plaimi.net/~alexander -----BEGIN PGP SIGNATURE----- Version: GnuPG v2
iQIcBAEBCgAGBQJWBTfiAAoJENQqWdRUGk8BU00QAMQfZo07CKomsjqcwNCDNqdm ifIhiz2kldR+A/gp6t/8IRf0RG3ZgZfwxhR5s/BWt7yV28napZfTMHPTfV8gE+bm V8AzvsXe/XLa9gTDyxqnY+ovYBDnEqmbX3SU03rRdtcN3jHiNuFkfIEIkRx6+HVx BKfoebxD7r1tgs/4nxjD8HljJEh6W8ux2Q8+sMWiCJEbVN5ixzTzGSk28vT2Ldyl GkoZJoXYM4K3WVCn23UmH9eokbdbnaCu2WRqzGgM7eQf+qqpouSjE3KRL5d9O/pE NMJIrNkC1L613GpfNeHLikOCKd78vbT0xnXyKHwAxv4Cr/7IZI3dyu+5MYwFntrY cdX7PgNQw7RN/tvZ63OOaRQEqvQfiOSdhPdFxAF5MabPNYMZMjIHqJuQseBaiUJf SWOU9oYNWW7XQVaQRVS5bP0KvRUhsA2+QXEd6pnhBEZ6u7qRQhaJowjca/A1TbB/ LHVG9nXE04fvc+CRkMK/xZEbuNWiMF0p4CZUiyeuAzhcZ9dge367ExfrTpTSLz8O Gfh04LgWs3rnvc3w8yhJJjcfsHhYZKQJMv40Rn8dgE/hyGFRpwQvBvFolZtFBZiS h6A/MyLDaSJCw3jwj+cU5PGLULGzdfNnTRlJ/jb4/CD2xUEOaQcAd+NvIJOlREcK RZBk4o5MU1aCsujOzjRd =VfnC -----END PGP SIGNATURE----- _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

It *should* be possible to recognize
return = pure
return x = pure x
pure = return
pure x = return x
and also cases where pure and return are defined the same up to alpha
equivalence. It should also be possible to fix this up automatically, but
there are several different fixes that programmers may want. Many package
maintainers strive to support old GHC versions--some as far back as
7.0--and a few even try to keep their code running in Hugs, although that
seems a bit silly. Those maintainers will probably want to use
MIN_VERSION_base to maintain backwards compatibility. Some of those
packages (e.g., containers) approximate fake versions of that macro for
non-cabal compilation, but such conditional definitions may occur in each
file separately or in a global include file.
On Sep 25, 2015 11:35 AM, "Greg Weber"
Is the upgrade automatable with tooling that analyzes Haskell source code? If so can we provide an executable that will automatically upgrade packages? Pull requests could even be sent automatically.
On Fri, Sep 25, 2015 at 5:02 AM, Alexander Berntsen
wrote: -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512
Enthusiastic +1 from me too, of course.
- -- Alexander alexander@plaimi.net https://secure.plaimi.net/~alexander -----BEGIN PGP SIGNATURE----- Version: GnuPG v2
iQIcBAEBCgAGBQJWBTfiAAoJENQqWdRUGk8BU00QAMQfZo07CKomsjqcwNCDNqdm ifIhiz2kldR+A/gp6t/8IRf0RG3ZgZfwxhR5s/BWt7yV28napZfTMHPTfV8gE+bm V8AzvsXe/XLa9gTDyxqnY+ovYBDnEqmbX3SU03rRdtcN3jHiNuFkfIEIkRx6+HVx BKfoebxD7r1tgs/4nxjD8HljJEh6W8ux2Q8+sMWiCJEbVN5ixzTzGSk28vT2Ldyl GkoZJoXYM4K3WVCn23UmH9eokbdbnaCu2WRqzGgM7eQf+qqpouSjE3KRL5d9O/pE NMJIrNkC1L613GpfNeHLikOCKd78vbT0xnXyKHwAxv4Cr/7IZI3dyu+5MYwFntrY cdX7PgNQw7RN/tvZ63OOaRQEqvQfiOSdhPdFxAF5MabPNYMZMjIHqJuQseBaiUJf SWOU9oYNWW7XQVaQRVS5bP0KvRUhsA2+QXEd6pnhBEZ6u7qRQhaJowjca/A1TbB/ LHVG9nXE04fvc+CRkMK/xZEbuNWiMF0p4CZUiyeuAzhcZ9dge367ExfrTpTSLz8O Gfh04LgWs3rnvc3w8yhJJjcfsHhYZKQJMv40Rn8dgE/hyGFRpwQvBvFolZtFBZiS h6A/MyLDaSJCw3jwj+cU5PGLULGzdfNnTRlJ/jb4/CD2xUEOaQcAd+NvIJOlREcK RZBk4o5MU1aCsujOzjRd =VfnC -----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

yes, an automated upgrade would need to do a backwards compatible upgrade
(inserrt macros, etc)
On Fri, Sep 25, 2015 at 8:46 AM, David Feuer
It *should* be possible to recognize
return = pure return x = pure x pure = return pure x = return x and also cases where pure and return are defined the same up to alpha equivalence. It should also be possible to fix this up automatically, but there are several different fixes that programmers may want. Many package maintainers strive to support old GHC versions--some as far back as 7.0--and a few even try to keep their code running in Hugs, although that seems a bit silly. Those maintainers will probably want to use MIN_VERSION_base to maintain backwards compatibility. Some of those packages (e.g., containers) approximate fake versions of that macro for non-cabal compilation, but such conditional definitions may occur in each file separately or in a global include file. On Sep 25, 2015 11:35 AM, "Greg Weber"
wrote: Is the upgrade automatable with tooling that analyzes Haskell source code? If so can we provide an executable that will automatically upgrade packages? Pull requests could even be sent automatically.
On Fri, Sep 25, 2015 at 5:02 AM, Alexander Berntsen
wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512
Enthusiastic +1 from me too, of course.
- -- Alexander alexander@plaimi.net https://secure.plaimi.net/~alexander -----BEGIN PGP SIGNATURE----- Version: GnuPG v2
iQIcBAEBCgAGBQJWBTfiAAoJENQqWdRUGk8BU00QAMQfZo07CKomsjqcwNCDNqdm ifIhiz2kldR+A/gp6t/8IRf0RG3ZgZfwxhR5s/BWt7yV28napZfTMHPTfV8gE+bm V8AzvsXe/XLa9gTDyxqnY+ovYBDnEqmbX3SU03rRdtcN3jHiNuFkfIEIkRx6+HVx BKfoebxD7r1tgs/4nxjD8HljJEh6W8ux2Q8+sMWiCJEbVN5ixzTzGSk28vT2Ldyl GkoZJoXYM4K3WVCn23UmH9eokbdbnaCu2WRqzGgM7eQf+qqpouSjE3KRL5d9O/pE NMJIrNkC1L613GpfNeHLikOCKd78vbT0xnXyKHwAxv4Cr/7IZI3dyu+5MYwFntrY cdX7PgNQw7RN/tvZ63OOaRQEqvQfiOSdhPdFxAF5MabPNYMZMjIHqJuQseBaiUJf SWOU9oYNWW7XQVaQRVS5bP0KvRUhsA2+QXEd6pnhBEZ6u7qRQhaJowjca/A1TbB/ LHVG9nXE04fvc+CRkMK/xZEbuNWiMF0p4CZUiyeuAzhcZ9dge367ExfrTpTSLz8O Gfh04LgWs3rnvc3w8yhJJjcfsHhYZKQJMv40Rn8dgE/hyGFRpwQvBvFolZtFBZiS h6A/MyLDaSJCw3jwj+cU5PGLULGzdfNnTRlJ/jb4/CD2xUEOaQcAd+NvIJOlREcK RZBk4o5MU1aCsujOzjRd =VfnC -----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 making this proposal.
I'm leery of the breakage that this would cause. But, there has been no chorus of voices complaining about breaking changes in the recent past (AMP and changes to Typeable are top on my mind), so perhaps our community is more tolerant of breakage than I would guess.
Given that, I'm +1 on this.
The one point of this proposal that's gotten some debate is preferring `pure` or preferring `return`. (I'm considering any contemplation of other names to be more noise than signal. Besides, I interpret most [all?] of those emails to be in varying degrees of jest.)
I vote for `pure` over `return`. Although some have pointed out that `return` feels more natural to those coming from other languages, it is a false friend [1]. `return` is emphatically not a language construct in Haskell, and it has no effect on flow control. On the other hand `pure` embeds a pure bit in an effectful computation. When I say do { x ; pure $ y }, `y` is indeed pure, as the function suggests. I think this is a much simpler approach than trying to convince skeptical Java programmers that `return` is nothing special.
Richard
[1]: https://en.wikipedia.org/wiki/False_friend
On Sep 24, 2015, at 5:43 PM, Herbert Valerio Riedel
Hello *,
Concluding AMP and MFP, We (David and I) proudly present you the final installment of the Monad trilogy:
Monad of no `return` Proposal =============================
TLDR: To complete the AMP, turn `Monad(return)` method into a top-level binding aliasing `Applicative(pure)`.
Current Situation -----------------
With the implementation of Functor-Applicative-Monad Proposal (AMP)[1] and (at some point) the MonadFail proposal (MFP)[2] the AMP class hierarchy becomes
class Functor f where fmap :: (a -> b) -> f a -> f b
class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b u *> v = …
(<*) :: f a -> f b -> f a u <* v = …
class Applicative m => Monad m where (>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a return = pure
(>>) :: m a -> m b -> m b m >> k = …
class Monad m => MonadFail m where fail :: String -> m a
Consequently, the `Monad` class is left with a now redundant `return` method as a historic artifact, as there's no compelling reason to have `pure` and `return` implemented differently.
Traditionally, `return` is often used where `pure` would suffice today, forcing a `Monad` constraint even if a weaker `Applicative` would have sufficed.
As a result, language extensions like `ApplicativeDo`[3] have to rewrite `return` to weaken its `Monad m =>` constraint to `Applicative m =>` in order to benefit existing code at the cost of introducing magic behavior at the type level.
Finally, this redundancy becomes even more significant when viewed in light of the renewed Haskell standardisation process[7]: The next Haskell Report will almost certainly incorporate the AMP (and MFP) changes, and there's no justification for the Report to retain `return` as a method of `Monad`. A good reason would have been to retain backward compatibility with Haskell 2010. However, as the AMP superclass hierarchy requires `Monad` instances to be accompanied by `Applicative` instances (which aren't part of Haskell 2010, c.f. [6]), backward compatibility with Haskell 2010 goes out the window when it comes to defining `Monad` instances (unless via use of `-XCPP` or similar). Consequently, meeting the high bar for a formal document such as the Haskell Report demands that `Monad` shall not carry a redundant `return` method that serves no purpose anymore. Moreover, getting `return` out of the way is desirable to facilitate standardising potential candidates such as the earlier mentioned `ApplicativeDo` in the future and avoids the technical debt incurred by keeping around this language wart.
Proposed Change ---------------
Remove `return` as a method from the `Monad` class and in its place define a top-level binding with the weaker `Applicative` typeclass constraint:
-- | Legacy alias for 'pure' return :: Applicative f => a -> f a return = pure
This allows existing code using `return` to benefit from a weaker typeclass constraint as well as cleaning the `Monad` class from a redundant method in the post-AMP world.
A possible migration strategy is described further below.
Compatibility Considerations ----------------------------
Generalizing the type signature of a function from a `Monad` constraint to its superclass `Applicative` doesn't cause new type-errors in existing code.
However, moving a method to a top-level binding obviously breaks code that assumes `return` to be a class method. Foremost, code that defines `Monad` instances it at risk:
### Instance Definitions
Code defining `return` as part of an instance definition breaks. However, we had the foresight to provide a default implementation in `base-4.8` for `return` so that the following represents a proper minimal instance definition post-AMP:
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
-- NB: No mention of `return`
Consequently, it is possible to write forward-compatible instances that are valid under this proposal starting with GHC 7.10/`base-4.8`.
Heuristically `grep`ing through Hackage source-code reveals a non-negligible number of packages defining `Monad` instances with explicit `return` definitions[4]. This has a comparable impact to the AMP, and similarly will require a transition scheme aided by compiler warnings.
### Module Import/Export Specifications
A second source of incompatibility may be due to `import`s. Specifically module import that assert `return` to be a method of `Monad`, e.g.:
import Control.Monad (Monad ((>>=), return))
or
import Prelude hiding (Monad(..)) import Control.Monad (Monad(..)) as Monad
f = Monad.return ()
The dual situation can occur when re-exporting `return` via module export specifications.
However, given that `return` is exported by `Prelude` and the examples above are rather artificial, we don't expect this to be a major source of breakage in the case of `return`. In fact, a heuristic grep[5] over Hackage source-code revealed only 21 packages affected.
### Example for writing compatible code
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
#if !(MIN_VERSION_base(4,8,0)) return = pure #endif
Migration Strategy ------------------
The migration strategy is straightforward:
**Phase 1** *(GHC 8.0)*: Implement new warning in GHC which gets triggered when `Monad` instances explicitly override the default `return` method implementation.
**Phase 2** *(GHC 8.2 or later)*: When we're confident that the majority of Hackage has reacted to the warning (with the help of Stackage actively pursuing maintainers to update their packages) we turn the `return` method into a top-level binding and remove the warning implemented in Phase 1 from GHC again.
Discussion period -----------------
A discussion period of three weeks (until 2015-10-15) should be enough to allow everyone to chime in as well as leave enough time to make the required preparations for GHC 8.0 should this proposal pass as we hope.
----
[1]: https://wiki.haskell.org/Functor-Applicative-Monad_Proposal [2]: https://wiki.haskell.org/MonadFail_Proposal [3]: https://ghc.haskell.org/trac/ghc/wiki/ApplicativeDo [4]: https://gist.github.com/hvr/b0e34463d85b58f169d9 [5]: https://gist.github.com/hvr/afcd040783d980594883 [6]: https://ghc.haskell.org/trac/ghc/ticket/9590 [7]: https://mail.haskell.org/pipermail/haskell-prime/2015-September/003936.html
-- _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

+0.5 on the overall proposal, -1 on breaking anything more in order to favor "pure" or "return". Both are iffy names. My issues with Richard's arguments against "pure": - Purity/effectful-ness and applicative/monadic are sorta orthogonal, e.g.: pure (print 0) :: [IO ()] - In the sense that "pure 7 :: IO Int" does actually take a pure thing and make it impure, it still has the opposite of function naming convention, namely describing what the function does to the value. It's a little like defining oneLess = (+1) and then saying "no, see, in 'oneLess 7'", 7 is one less than the result" Tom
El 26 sept 2015, a las 18:04, Richard Eisenberg
escribió: Thanks for making this proposal.
I'm leery of the breakage that this would cause. But, there has been no chorus of voices complaining about breaking changes in the recent past (AMP and changes to Typeable are top on my mind), so perhaps our community is more tolerant of breakage than I would guess.
Given that, I'm +1 on this.
The one point of this proposal that's gotten some debate is preferring `pure` or preferring `return`. (I'm considering any contemplation of other names to be more noise than signal. Besides, I interpret most [all?] of those emails to be in varying degrees of jest.)
I vote for `pure` over `return`. Although some have pointed out that `return` feels more natural to those coming from other languages, it is a false friend [1]. `return` is emphatically not a language construct in Haskell, and it has no effect on flow control. On the other hand `pure` embeds a pure bit in an effectful computation. When I say do { x ; pure $ y }, `y` is indeed pure, as the function suggests. I think this is a much simpler approach than trying to convince skeptical Java programmers that `return` is nothing special.
Richard
[1]: https://en.wikipedia.org/wiki/False_friend
On Sep 24, 2015, at 5:43 PM, Herbert Valerio Riedel
wrote: Hello *,
Concluding AMP and MFP, We (David and I) proudly present you the final installment of the Monad trilogy:
Monad of no `return` Proposal =============================
TLDR: To complete the AMP, turn `Monad(return)` method into a top-level binding aliasing `Applicative(pure)`.
Current Situation -----------------
With the implementation of Functor-Applicative-Monad Proposal (AMP)[1] and (at some point) the MonadFail proposal (MFP)[2] the AMP class hierarchy becomes
class Functor f where fmap :: (a -> b) -> f a -> f b
class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b u *> v = …
(<*) :: f a -> f b -> f a u <* v = …
class Applicative m => Monad m where (>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a return = pure
(>>) :: m a -> m b -> m b m >> k = …
class Monad m => MonadFail m where fail :: String -> m a
Consequently, the `Monad` class is left with a now redundant `return` method as a historic artifact, as there's no compelling reason to have `pure` and `return` implemented differently.
Traditionally, `return` is often used where `pure` would suffice today, forcing a `Monad` constraint even if a weaker `Applicative` would have sufficed.
As a result, language extensions like `ApplicativeDo`[3] have to rewrite `return` to weaken its `Monad m =>` constraint to `Applicative m =>` in order to benefit existing code at the cost of introducing magic behavior at the type level.
Finally, this redundancy becomes even more significant when viewed in light of the renewed Haskell standardisation process[7]: The next Haskell Report will almost certainly incorporate the AMP (and MFP) changes, and there's no justification for the Report to retain `return` as a method of `Monad`. A good reason would have been to retain backward compatibility with Haskell 2010. However, as the AMP superclass hierarchy requires `Monad` instances to be accompanied by `Applicative` instances (which aren't part of Haskell 2010, c.f. [6]), backward compatibility with Haskell 2010 goes out the window when it comes to defining `Monad` instances (unless via use of `-XCPP` or similar). Consequently, meeting the high bar for a formal document such as the Haskell Report demands that `Monad` shall not carry a redundant `return` method that serves no purpose anymore. Moreover, getting `return` out of the way is desirable to facilitate standardising potential candidates such as the earlier mentioned `ApplicativeDo` in the future and avoids the technical debt incurred by keeping around this language wart.
Proposed Change ---------------
Remove `return` as a method from the `Monad` class and in its place define a top-level binding with the weaker `Applicative` typeclass constraint:
-- | Legacy alias for 'pure' return :: Applicative f => a -> f a return = pure
This allows existing code using `return` to benefit from a weaker typeclass constraint as well as cleaning the `Monad` class from a redundant method in the post-AMP world.
A possible migration strategy is described further below.
Compatibility Considerations ----------------------------
Generalizing the type signature of a function from a `Monad` constraint to its superclass `Applicative` doesn't cause new type-errors in existing code.
However, moving a method to a top-level binding obviously breaks code that assumes `return` to be a class method. Foremost, code that defines `Monad` instances it at risk:
### Instance Definitions
Code defining `return` as part of an instance definition breaks. However, we had the foresight to provide a default implementation in `base-4.8` for `return` so that the following represents a proper minimal instance definition post-AMP:
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
-- NB: No mention of `return`
Consequently, it is possible to write forward-compatible instances that are valid under this proposal starting with GHC 7.10/`base-4.8`.
Heuristically `grep`ing through Hackage source-code reveals a non-negligible number of packages defining `Monad` instances with explicit `return` definitions[4]. This has a comparable impact to the AMP, and similarly will require a transition scheme aided by compiler warnings.
### Module Import/Export Specifications
A second source of incompatibility may be due to `import`s. Specifically module import that assert `return` to be a method of `Monad`, e.g.:
import Control.Monad (Monad ((>>=), return))
or
import Prelude hiding (Monad(..)) import Control.Monad (Monad(..)) as Monad
f = Monad.return ()
The dual situation can occur when re-exporting `return` via module export specifications.
However, given that `return` is exported by `Prelude` and the examples above are rather artificial, we don't expect this to be a major source of breakage in the case of `return`. In fact, a heuristic grep[5] over Hackage source-code revealed only 21 packages affected.
### Example for writing compatible code
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
#if !(MIN_VERSION_base(4,8,0)) return = pure #endif
Migration Strategy ------------------
The migration strategy is straightforward:
**Phase 1** *(GHC 8.0)*: Implement new warning in GHC which gets triggered when `Monad` instances explicitly override the default `return` method implementation.
**Phase 2** *(GHC 8.2 or later)*: When we're confident that the majority of Hackage has reacted to the warning (with the help of Stackage actively pursuing maintainers to update their packages) we turn the `return` method into a top-level binding and remove the warning implemented in Phase 1 from GHC again.
Discussion period -----------------
A discussion period of three weeks (until 2015-10-15) should be enough to allow everyone to chime in as well as leave enough time to make the required preparations for GHC 8.0 should this proposal pass as we hope.
----
[1]: https://wiki.haskell.org/Functor-Applicative-Monad_Proposal [2]: https://wiki.haskell.org/MonadFail_Proposal [3]: https://ghc.haskell.org/trac/ghc/wiki/ApplicativeDo [4]: https://gist.github.com/hvr/b0e34463d85b58f169d9 [5]: https://gist.github.com/hvr/afcd040783d980594883 [6]: https://ghc.haskell.org/trac/ghc/ticket/9590 [7]: https://mail.haskell.org/pipermail/haskell-prime/2015-September/003936.html
-- _______________________________________________ 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

Richard Eisenberg
writes:
I'm leery of the breakage that this would cause. But, there has been no chorus of voices complaining about breaking changes in the recent past (AMP and changes to Typeable are top on my mind), so perhaps our community is more tolerant of breakage than I would guess.
Also, the breakage argument never resolves itself with time, so if it's always heeded, we simply cannot progress toward the solution most of us would have chosen from the beginning, had we foreknowledge of things to come. I think it's a great thing we're enduring the pain now to correct past decisions, and move toward a cleaner theoretic foundation. As for pure vs. return: What I like about 'pure' is that it declaratively says something about the value, rather than the action constructed from that value. It says "this action has no other semantics than what can be determined from the value itself". John

IME the community has a group that's highly skeptical of breaking changes
with little-to-no benefit. Renaming either pure or return I think would
qualify, as the breakage would be extensive, and the resulting language
would be identical modulo the renaming, i.e. no extra expressiveness is
granted. AMP addressed a long-standing pain point of the language and had
a well-thought-out transition scheme, and Typeable is only rarely used by
hand so the breakage wasn't actually that extensive.
My biggest concern with this proposal is the breakage of
mostly-unmaintained but working packages. As with ekmett, I'm in favor
provided that there's a sufficiently well-planned transition period.
Providing a minor ghc release that warns about any superfluous 'return'
definitions would be very helpful.
On Sat, Sep 26, 2015 at 5:05 PM Richard Eisenberg
Thanks for making this proposal.
I'm leery of the breakage that this would cause. But, there has been no chorus of voices complaining about breaking changes in the recent past (AMP and changes to Typeable are top on my mind), so perhaps our community is more tolerant of breakage than I would guess.
Given that, I'm +1 on this.
The one point of this proposal that's gotten some debate is preferring `pure` or preferring `return`. (I'm considering any contemplation of other names to be more noise than signal. Besides, I interpret most [all?] of those emails to be in varying degrees of jest.)
I vote for `pure` over `return`. Although some have pointed out that `return` feels more natural to those coming from other languages, it is a false friend [1]. `return` is emphatically not a language construct in Haskell, and it has no effect on flow control. On the other hand `pure` embeds a pure bit in an effectful computation. When I say do { x ; pure $ y }, `y` is indeed pure, as the function suggests. I think this is a much simpler approach than trying to convince skeptical Java programmers that `return` is nothing special.
Richard
[1]: https://en.wikipedia.org/wiki/False_friend
On Sep 24, 2015, at 5:43 PM, Herbert Valerio Riedel
wrote: Hello *,
Concluding AMP and MFP, We (David and I) proudly present you the final installment of the Monad trilogy:
Monad of no `return` Proposal =============================
TLDR: To complete the AMP, turn `Monad(return)` method into a top-level binding aliasing `Applicative(pure)`.
Current Situation -----------------
With the implementation of Functor-Applicative-Monad Proposal (AMP)[1] and (at some point) the MonadFail proposal (MFP)[2] the AMP class hierarchy becomes
class Functor f where fmap :: (a -> b) -> f a -> f b
class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b u *> v = …
(<*) :: f a -> f b -> f a u <* v = …
class Applicative m => Monad m where (>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a return = pure
(>>) :: m a -> m b -> m b m >> k = …
class Monad m => MonadFail m where fail :: String -> m a
Consequently, the `Monad` class is left with a now redundant `return` method as a historic artifact, as there's no compelling reason to have `pure` and `return` implemented differently.
Traditionally, `return` is often used where `pure` would suffice today, forcing a `Monad` constraint even if a weaker `Applicative` would have sufficed.
As a result, language extensions like `ApplicativeDo`[3] have to rewrite `return` to weaken its `Monad m =>` constraint to `Applicative m =>` in order to benefit existing code at the cost of introducing magic behavior at the type level.
Finally, this redundancy becomes even more significant when viewed in light of the renewed Haskell standardisation process[7]: The next Haskell Report will almost certainly incorporate the AMP (and MFP) changes, and there's no justification for the Report to retain `return` as a method of `Monad`. A good reason would have been to retain backward compatibility with Haskell 2010. However, as the AMP superclass hierarchy requires `Monad` instances to be accompanied by `Applicative` instances (which aren't part of Haskell 2010, c.f. [6]), backward compatibility with Haskell 2010 goes out the window when it comes to defining `Monad` instances (unless via use of `-XCPP` or similar). Consequently, meeting the high bar for a formal document such as the Haskell Report demands that `Monad` shall not carry a redundant `return` method that serves no purpose anymore. Moreover, getting `return` out of the way is desirable to facilitate standardising potential candidates such as the earlier mentioned `ApplicativeDo` in the future and avoids the technical debt incurred by keeping around this language wart.
Proposed Change ---------------
Remove `return` as a method from the `Monad` class and in its place define a top-level binding with the weaker `Applicative` typeclass constraint:
-- | Legacy alias for 'pure' return :: Applicative f => a -> f a return = pure
This allows existing code using `return` to benefit from a weaker typeclass constraint as well as cleaning the `Monad` class from a redundant method in the post-AMP world.
A possible migration strategy is described further below.
Compatibility Considerations ----------------------------
Generalizing the type signature of a function from a `Monad` constraint to its superclass `Applicative` doesn't cause new type-errors in existing code.
However, moving a method to a top-level binding obviously breaks code that assumes `return` to be a class method. Foremost, code that defines `Monad` instances it at risk:
### Instance Definitions
Code defining `return` as part of an instance definition breaks. However, we had the foresight to provide a default implementation in `base-4.8` for `return` so that the following represents a proper minimal instance definition post-AMP:
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
-- NB: No mention of `return`
Consequently, it is possible to write forward-compatible instances that are valid under this proposal starting with GHC 7.10/`base-4.8`.
Heuristically `grep`ing through Hackage source-code reveals a non-negligible number of packages defining `Monad` instances with explicit `return` definitions[4]. This has a comparable impact to the AMP, and similarly will require a transition scheme aided by compiler warnings.
### Module Import/Export Specifications
A second source of incompatibility may be due to `import`s. Specifically module import that assert `return` to be a method of `Monad`, e.g.:
import Control.Monad (Monad ((>>=), return))
or
import Prelude hiding (Monad(..)) import Control.Monad (Monad(..)) as Monad
f = Monad.return ()
The dual situation can occur when re-exporting `return` via module export specifications.
However, given that `return` is exported by `Prelude` and the examples above are rather artificial, we don't expect this to be a major source of breakage in the case of `return`. In fact, a heuristic grep[5] over Hackage source-code revealed only 21 packages affected.
### Example for writing compatible code
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
#if !(MIN_VERSION_base(4,8,0)) return = pure #endif
Migration Strategy ------------------
The migration strategy is straightforward:
**Phase 1** *(GHC 8.0)*: Implement new warning in GHC which gets triggered when `Monad` instances explicitly override the default `return` method implementation.
**Phase 2** *(GHC 8.2 or later)*: When we're confident that the majority of Hackage has reacted to the warning (with the help of Stackage actively pursuing maintainers to update their packages) we turn the `return` method into a top-level binding and remove the warning implemented in Phase 1 from GHC again.
Discussion period -----------------
A discussion period of three weeks (until 2015-10-15) should be enough to allow everyone to chime in as well as leave enough time to make the required preparations for GHC 8.0 should this proposal pass as we hope.
----
[1]: https://wiki.haskell.org/Functor-Applicative-Monad_Proposal [2]: https://wiki.haskell.org/MonadFail_Proposal [3]: https://ghc.haskell.org/trac/ghc/wiki/ApplicativeDo [4]: https://gist.github.com/hvr/b0e34463d85b58f169d9 [5]: https://gist.github.com/hvr/afcd040783d980594883 [6]: https://ghc.haskell.org/trac/ghc/ticket/9590 [7]: https://mail.haskell.org/pipermail/haskell-prime/2015-September/003936.html
-- _______________________________________________ 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 Sat, Sep 26, 2015 at 6:04 PM, Richard Eisenberg
Thanks for making this proposal.
I'm leery of the breakage that this would cause. But, there has been no chorus of voices complaining about breaking changes in the recent past (AMP and changes to Typeable are top on my mind), so perhaps our community is more tolerant of breakage than I would guess.
Though I'd love to see pure/return unified, I almost wonder if it'd be a good idea to wait a bit on this. By which I mean, rather than having a bunch of little breaking changes as we try to fix things piecemeal, perhaps it'd be better to fold this proposal (and similar ones) into the next Haskell' report (assuming we can actually ship it this time). That way we can just have a big break-the-world change in the transition to Haskell2020 (or whatever). Not sure if that's the best approach, especially given the difficulty in getting Haskell2020 finalized, but it might be worth thinking about... -- Live well, ~wren

+1
Regards,
Malcolm (iPhone)
On 28 Sep 2015, at 22:42, wren romano
On Sat, Sep 26, 2015 at 6:04 PM, Richard Eisenberg
wrote: Thanks for making this proposal. I'm leery of the breakage that this would cause. But, there has been no chorus of voices complaining about breaking changes in the recent past (AMP and changes to Typeable are top on my mind), so perhaps our community is more tolerant of breakage than I would guess.
Though I'd love to see pure/return unified, I almost wonder if it'd be a good idea to wait a bit on this. By which I mean, rather than having a bunch of little breaking changes as we try to fix things piecemeal, perhaps it'd be better to fold this proposal (and similar ones) into the next Haskell' report (assuming we can actually ship it this time). That way we can just have a big break-the-world change in the transition to Haskell2020 (or whatever). Not sure if that's the best approach, especially given the difficulty in getting Haskell2020 finalized, but it might be worth thinking about... -- Live well, ~wren _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

The standard is pretty much what was driving the timing of this proposal.
With warnings put in place in 8.0, we can have the situation set up so that
this process completes in time for a Haskell 2017 that incorporates much of
the current state of the world, AMP, Foldable/Traversable, etc.
Then knock-on effects like Traversable simplification can be in place by a
Haskell 2020, which can try to be more ambitious.
If we don't start it now, however, then we won't have sufficient warning
time for users.
On Mon, Sep 28, 2015 at 5:42 PM, wren romano
On Sat, Sep 26, 2015 at 6:04 PM, Richard Eisenberg
wrote: Thanks for making this proposal.
I'm leery of the breakage that this would cause. But, there has been no chorus of voices complaining about breaking changes in the recent past (AMP and changes to Typeable are top on my mind), so perhaps our community is more tolerant of breakage than I would guess.
Though I'd love to see pure/return unified, I almost wonder if it'd be a good idea to wait a bit on this. By which I mean, rather than having a bunch of little breaking changes as we try to fix things piecemeal, perhaps it'd be better to fold this proposal (and similar ones) into the next Haskell' report (assuming we can actually ship it this time). That way we can just have a big break-the-world change in the transition to Haskell2020 (or whatever).
Not sure if that's the best approach, especially given the difficulty in getting Haskell2020 finalized, but it might be worth thinking about...
-- Live well, ~wren _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

For the benefit of people trying out code from papers, tutorials, etc.,
would it be possible to craft a permanent custom error message for explicit
return definitions? I don't remember AMP having such for the new
constraint; if it doesn't, maybe it should.
On Sep 24, 2015 5:43 PM, "Herbert Valerio Riedel"
Hello *,
Concluding AMP and MFP, We (David and I) proudly present you the final installment of the Monad trilogy:
Monad of no `return` Proposal =============================
TLDR: To complete the AMP, turn `Monad(return)` method into a top-level binding aliasing `Applicative(pure)`.
Current Situation -----------------
With the implementation of Functor-Applicative-Monad Proposal (AMP)[1] and (at some point) the MonadFail proposal (MFP)[2] the AMP class hierarchy becomes
class Functor f where fmap :: (a -> b) -> f a -> f b
class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b u *> v = …
(<*) :: f a -> f b -> f a u <* v = …
class Applicative m => Monad m where (>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a return = pure
(>>) :: m a -> m b -> m b m >> k = …
class Monad m => MonadFail m where fail :: String -> m a
Consequently, the `Monad` class is left with a now redundant `return` method as a historic artifact, as there's no compelling reason to have `pure` and `return` implemented differently.
Traditionally, `return` is often used where `pure` would suffice today, forcing a `Monad` constraint even if a weaker `Applicative` would have sufficed.
As a result, language extensions like `ApplicativeDo`[3] have to rewrite `return` to weaken its `Monad m =>` constraint to `Applicative m =>` in order to benefit existing code at the cost of introducing magic behavior at the type level.
Finally, this redundancy becomes even more significant when viewed in light of the renewed Haskell standardisation process[7]: The next Haskell Report will almost certainly incorporate the AMP (and MFP) changes, and there's no justification for the Report to retain `return` as a method of `Monad`. A good reason would have been to retain backward compatibility with Haskell 2010. However, as the AMP superclass hierarchy requires `Monad` instances to be accompanied by `Applicative` instances (which aren't part of Haskell 2010, c.f. [6]), backward compatibility with Haskell 2010 goes out the window when it comes to defining `Monad` instances (unless via use of `-XCPP` or similar). Consequently, meeting the high bar for a formal document such as the Haskell Report demands that `Monad` shall not carry a redundant `return` method that serves no purpose anymore. Moreover, getting `return` out of the way is desirable to facilitate standardising potential candidates such as the earlier mentioned `ApplicativeDo` in the future and avoids the technical debt incurred by keeping around this language wart.
Proposed Change ---------------
Remove `return` as a method from the `Monad` class and in its place define a top-level binding with the weaker `Applicative` typeclass constraint:
-- | Legacy alias for 'pure' return :: Applicative f => a -> f a return = pure
This allows existing code using `return` to benefit from a weaker typeclass constraint as well as cleaning the `Monad` class from a redundant method in the post-AMP world.
A possible migration strategy is described further below.
Compatibility Considerations ----------------------------
Generalizing the type signature of a function from a `Monad` constraint to its superclass `Applicative` doesn't cause new type-errors in existing code.
However, moving a method to a top-level binding obviously breaks code that assumes `return` to be a class method. Foremost, code that defines `Monad` instances it at risk:
### Instance Definitions
Code defining `return` as part of an instance definition breaks. However, we had the foresight to provide a default implementation in `base-4.8` for `return` so that the following represents a proper minimal instance definition post-AMP:
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
-- NB: No mention of `return`
Consequently, it is possible to write forward-compatible instances that are valid under this proposal starting with GHC 7.10/`base-4.8`.
Heuristically `grep`ing through Hackage source-code reveals a non-negligible number of packages defining `Monad` instances with explicit `return` definitions[4]. This has a comparable impact to the AMP, and similarly will require a transition scheme aided by compiler warnings.
### Module Import/Export Specifications
A second source of incompatibility may be due to `import`s. Specifically module import that assert `return` to be a method of `Monad`, e.g.:
import Control.Monad (Monad ((>>=), return))
or
import Prelude hiding (Monad(..)) import Control.Monad (Monad(..)) as Monad
f = Monad.return ()
The dual situation can occur when re-exporting `return` via module export specifications.
However, given that `return` is exported by `Prelude` and the examples above are rather artificial, we don't expect this to be a major source of breakage in the case of `return`. In fact, a heuristic grep[5] over Hackage source-code revealed only 21 packages affected.
### Example for writing compatible code
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
#if !(MIN_VERSION_base(4,8,0)) return = pure #endif
Migration Strategy ------------------
The migration strategy is straightforward:
**Phase 1** *(GHC 8.0)*: Implement new warning in GHC which gets triggered when `Monad` instances explicitly override the default `return` method implementation.
**Phase 2** *(GHC 8.2 or later)*: When we're confident that the majority of Hackage has reacted to the warning (with the help of Stackage actively pursuing maintainers to update their packages) we turn the `return` method into a top-level binding and remove the warning implemented in Phase 1 from GHC again.
Discussion period -----------------
A discussion period of three weeks (until 2015-10-15) should be enough to allow everyone to chime in as well as leave enough time to make the required preparations for GHC 8.0 should this proposal pass as we hope.
----
[1]: https://wiki.haskell.org/Functor-Applicative-Monad_Proposal [2]: https://wiki.haskell.org/MonadFail_Proposal [3]: https://ghc.haskell.org/trac/ghc/wiki/ApplicativeDo [4]: https://gist.github.com/hvr/b0e34463d85b58f169d9 [5]: https://gist.github.com/hvr/afcd040783d980594883 [6]: https://ghc.haskell.org/trac/ghc/ticket/9590 [7]: https://mail.haskell.org/pipermail/haskell-prime/2015-September/003936.html
--
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

On 28.09.2015 00:16, David Feuer wrote:
For the benefit of people trying out code from papers, tutorials, etc., would it be possible to craft a permanent custom error message for explicit return definitions? I don't remember AMP having such for the new constraint; if it doesn't, maybe it should.
Sure, that's something we can probably do. I've done some (futile) digging in GHC, but the plan is to implement this as a "if a Monad definition contains a binding referring to 'return' emit a warning", which is or can be made orthogonal of there actually being a "return" in the actual class.

On Sep 27, 2015, at 6:22 PM, David Luposchainsky
On 28.09.2015 00:16, David Feuer wrote:
For the benefit of people trying out code from papers, tutorials, etc., would it be possible to craft a permanent custom error message for explicit return definitions? I don't remember AMP having such for the new constraint; if it doesn't, maybe it should.
Sure, that's something we can probably do. I've done some (futile) digging in GHC, but the plan is to implement this as a "if a Monad definition contains a binding referring to 'return' emit a warning", which is or can be made orthogonal of there actually being a "return" in the actual class.
I like this idea -- I, for one, often forget to consider the effect legacy written material has. But if we're doing this for Monad, why not just come up with a pragma so that the magic doesn't have to be baked in? As in, witness the new definition for Monad:
class Applicative m => Monad m where ... {-# REMOVED return "The `return` method has been removed from Monad. Use `pure` in Applicative instead" #-}
(Please fix my warning text.) We people with direct access to GHC might not be the only ones who want to refactor a method out from a class. Richard
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

On Sep 27, 2015 9:56 PM, "Richard Eisenberg"
I like this idea -- I, for one, often forget to consider the effect
legacy written material has. But if we're doing this for Monad, why not just come up with a pragma so that the magic doesn't have to be baked in? As in, witness the new definition for Monad:
class Applicative m => Monad m where ... {-# REMOVED return "The `return` method has been removed from Monad.
Use `pure` in Applicative instead" #-}
(Please fix my warning text.)
We people with direct access to GHC might not be the only ones who want
to refactor a method out from a class. That's an excellent idea, and I think it makes sense to offer it at the module level as well as the class level. Just change DEPRECATED to REMOVED when it's actually removed. Speaking of such, has the deprecated export proposal made any headway? David Feuer

On 2015-09-28 at 04:56:13 +0200, David Feuer wrote: [...]
That's an excellent idea, and I think it makes sense to offer it at the module level as well as the class level. Just change DEPRECATED to REMOVED when it's actually removed. Speaking of such, has the deprecated export proposal made any headway?
As far as the in-flight library proposals are concerned, I plan to rather have hardwired specific warnings implemented in the style of the AMP warnings as it's crucial to have them available for the GHC 8.0 release to have the foundations for the migration plans in place. We can generalize those feature later-on (maybe even in time for GHC 8.0 if we're lucky). ---- As for the more general facilities the short answer is: They're stalled! Volunteers wanted! There's the specification over at - https://ghc.haskell.org/trac/ghc/wiki/Design/MethodDeprecations and there are 3 somewhat connected/related warning-feature tickets which ought to be co-designed to avoid obstructing each other (if there's any risk there). - https://ghc.haskell.org/trac/ghc/ticket/10071 - https://ghc.haskell.org/trac/ghc/ticket/2119 - https://ghc.haskell.org/trac/ghc/ticket/4879 For #10071 there's a very modest start at implementing this, which just modifies the parser but doesn't go much farther (see wip/T10071 branch) There's an old patch for #4879 which still works over at - https://phabricator.haskell.org/D638 Cheers, hvr

On Sun, 27 Sep 2015, David Feuer wrote:
On Sep 27, 2015 9:56 PM, "Richard Eisenberg"
wrote: I like this idea -- I, for one, often forget to consider the effect legacy written material has. But if we're doing
this for Monad, why not just come up with a pragma so that the magic doesn't have to be baked in? As in, witness the new definition for Monad:
class Applicative m => Monad m where ... {-# REMOVED return "The `return` method has been removed from Monad. Use `pure` in Applicative instead" #-}
(Please fix my warning text.)
We people with direct access to GHC might not be the only ones who want to refactor a method out from a class.
That's an excellent idea, and I think it makes sense to offer it at the module level as well as the class level. Just change DEPRECATED to REMOVED when it's actually removed. Speaking of such, has the deprecated export proposal made any headway?
I like the idea of a REMOVED pragma very much. After a deprecated function is actually removed it is hard to find out how to fix the code. I often ignore DEPRECATED warnings because respecting them would break my code for older GHC versions.

On Thu, 24 Sep 2015, Herbert Valerio Riedel wrote:
Consequently, the `Monad` class is left with a now redundant `return` method as a historic artifact, as there's no compelling reason to have `pure` and `return` implemented differently.
Traditionally, `return` is often used where `pure` would suffice today, forcing a `Monad` constraint even if a weaker `Applicative` would have sufficed.
I do not see why this proposal is necessary and urgent. Over the past years several redundant methods where added to type classes in order to allow for optimized implementations. Without much investigation I remember Foldable.sum, Foldable.product, ..., Applicative.*>, Applicative.<*, Functor.<$, Bits.zeroBits and discussions about Monad.join. Although I think that it is never possible to implement 'return' more efficiently than 'pure', we could pretend for now that it is possible. :-) At least, leaving 'return' does not hurt much. My practical concern is that the change will break every current Monad instance for no benefit and I would not be able to write code that works for current and past GHC versions.
As a result, language extensions like `ApplicativeDo`[3] have to rewrite `return` to weaken its `Monad m =>` constraint to `Applicative m =>` in order to benefit existing code at the cost of introducing magic behavior at the type level.
Like Henrik Nilsson, I wonder why people cannot replace 'return' by 'pure' if they want to make use of ApplicativeDo. I think the people who want a new feature should adapt their code. Why should I break my Monad instances instead?
Consequently, it is possible to write forward-compatible instances that are valid under this proposal starting with GHC 7.10/`base-4.8`.
Because the completely unrelated bug [1] affects several of my packages, I can use forward-compatible instances only starting with GHC-8.0. Bugs like this one also underline why it is so important to write code that works across multiple versions of GHC. Otherwise it's easily possible that a program depends on a set of packages that cannot be compiled by any GHC version. If you are very keen to remove 'return' I would ask you to wait some more release cycles of GHC. [1] https://ghc.haskell.org/trac/ghc/ticket/10009

On 01.10.2015 19:03, Henning Thielemann wrote:
Over the past years several redundant methods where added to type classes in order to allow for optimized implementations.
There's an important difference: *> is redundant, but not superflous. return on the other hand offers zero new functionality.
At least, leaving 'return' does not hurt much.
I guess that's a matter of what we want the standard to be. I think it should be the guideline to "a good Haskell" that compilers should aim to implement. If it takes GHC a couple of releases to become Report compliant then that's something I'm OK with.
My practical concern is that the change will break every current Monad instance for no benefit and I would not be able to write code that works for current and past GHC versions.
Monad instances written before 7.8. As of 7.10, return is not part of the minimal definition of Monad anymore, so starting with the current release, you're already able to write future-proof instances. That said, the issue with GHC < 7.10 remains of course.
If you are very keen to remove 'return' I would ask you to wait some more release cycles of GHC.
Of course! The next release will do nothing but issue (a disable-able) warning when an instance implements return. Beyond that, who knows, but it surely won't be breaking half of `cabal build` because of impatience. Greetings, David/quchen

Hi all, I have discussed the monad of no return proposal with my colleague Graham Hutton: a long-standing member of the Haskell community, well-known researcher, some 20 years of experience of teaching Haskell to undergraduate students, and author of one of the most successful introductory Haskell textbooks there are. The upshot of this e-mail is a strong collective -2 from us both on particular proposal, and a general call for much more caution when it comes to breaking changes that are not critically important. First, on a general note, there has recently been a flurry of breaking changes to the (de facto) Haskell standards. In many cases for very good reasons, but sometimes it seems more in a quest for perfection without due consideration for the consequences. It used to be the case that breaking changes were very rare indeed. And for good reason. Right now, the main "measure of breakage" in the on-line discussions seems to be how many packages that break in Hackage. Which of course makes sense: the Hackage repository is very important and such a measure is objective, as far as it goes. But we should not forget that breakage can go far beyond Hackage. For starters, there is *lots* of code that is not in Hackage, yet critically important to its users, however many or few they are. There are more than hundreds of thousands of copies of books out there where that may break in that examples may no longer work. And they cannot be changed. There are countless research papers that may break in the same way. Every single institution that use Haskell in their teaching may have to update their teaching materials (slides, code, lab instructions) for every module that teaches or uses Haskell. And last but not the least, what countless of programmers and students have learned about Haskell over decades, most of whom are *not* power users who can take these changes in their stride, may also break. Now, of course a language has to evolve, and sometimes breaking backwards compatibility is more or less essential for the long-term benefit of the language. But we should not let perfection be the enemy of the good. As to this particular proposal, the monad of no return, it does not seem essential to us, but mostly motivated by a quest for "perfection" as defined by a very knowledgeable but in relative terms small group of people. One argument put forward was that applicative code that uses "return" instead of "pure" should get a less constrained type. But such code is relatively new. The methods of the Monad class have been return and bind for some 25 years. So indeed, as Henning Thielemann wrote: why should not the newer code be adapted and use "pure" instead? In fact, the use of "pure" in such code could serve as a quite useful cue that the code is applicative rather than monadic, especially where applicative do is employed. Another reason put forward is support for the applicative do syntax. But that is, in standard terms, only a future possibility at this point. Further, the syntax is arguably rather dubious anyway as it, in particular to someone with an imperative background, suggests a sequential reading which is exactly what applicative is not and why it is useful. So from that perspective, using the applicative operators directly, without any syntactic sugar, actually amounts to a much more transparent and honest syntax, even if a bit more verbose in some cases. The bottom line is that it is premature to put forward support for the applicative do syntax as a rationale for a non-essential breaking change. Best regards, Henrik Nilsson and Graham Hutton -- Henrik Nilsson School of Computer Science The University of Nottingham nhn@cs.nott.ac.uk This message and any attachment are intended solely for the addressee and may contain confidential information. If you have received this message in error, please send it back to me, and immediately delete it. Please do not use, copy or disclose the information contained in this message or in any attachment. Any views or opinions expressed by the author of this email do not necessarily reflect the views of the University of Nottingham. This message has been checked for viruses but the contents of an attachment may still contain software viruses which could damage your computer system, you are advised to perform your own checks. Email communications with the University of Nottingham may be monitored as permitted by UK legislation.

On 10/02/2015 12:09 PM, Henrik Nilsson wrote:
Hi all,
[--snip--]
Another reason put forward is support for the applicative do syntax. But that is, in standard terms, only a future possibility at this point. Further, the syntax is arguably rather dubious anyway as it, in particular to someone with an imperative background, suggests a sequential reading which is exactly what applicative is not and why it is useful. So from that perspective, using the applicative operators directly, without any syntactic sugar, actually amounts to a much more transparent and honest syntax, even if a bit more verbose in some cases.
"Verbose" is the understatement of the year. There's a lot of code where ApplicativeDo makes the difference between "readable" and "unreadable". Like it or not, but programmers are used to *naming things* (even locally) and using those local names to refer to things. "Random" combinations of <$> and/or <*> and/or... (whatever) with no concrete meaningful names don't really work if you're working with concrete CRUD-like data. (Fine, if you're working with very abstract things then you might not even have meaningful names and so they lose their value. This is *not* the universal experience.) I should also say: I certainly *understand* the textbook argument, but if we're going that way, then we're going to end up like C++... before C++11/C++14. The C++ community/committee have realised their mistake (stagnatiation) and resolved to instead produce more/better/newer textbooks. For the better, IMO. We can certainly argue over individual changes, but this is not a good *general* argument against change. Have you surveyed the actual number of books out there which show how to implement Monad instances and how many of them would be affected? Regards,

speaking not about this particular "return" issue but change as such: change can be a) avoided or b) accommodated. let's think of abstract languages L and N. Any resemblance is coincidental and irrelevant. Suppose that: a significant codebase written in L is available N is a new language with few libraries a beginner programmer A.B. considers to dedicate their time and effort to either L or N A.B. prefers (for various reasons) N syntax. an experienced programmer C.D. dedicated their time to L language. C.D. is comfortable with L, wrote and use L code. C.D. can see some advantages language N gives over L. the number of programmers similar to C.D. (the L crowd) is fairly stable but who knows: C.D. may join the N crowd. number of A.B. and other undecided programmers varies. The more are A.B.'s, the larger is future camp of any language: L, N, ... let's think. This is not to argue pro/con but to put things in perspective. If you were in A.B.'s shoes, what would you do?

On 10/02/2015 11:38 PM, Imants Cekusins wrote:
speaking not about this particular "return" issue but change as such:
change can be a) avoided or b) accommodated.
let's think of abstract languages L and N. Any resemblance is coincidental and irrelevant.
(snip) I'm sorry, but you're going to have to put that in "working programmer" terms, at least if I'm ever going to understand it. Like most working programmers, I personally don't thrive on formal semantics/methods (though I do often benefit from them, even unknowingly!). Can you explain the problem in layman's terms? Regards,

Can you explain
that paragraph was not a problem but analogy. Here is a pared down version : if given choice, what would you and beginners prefer : libraries (no change, libraries work) or better syntax (change, libraries break)? please do not apply this to this particular issue ("return"). Which syntax is better, whether libraries break, is a different question.

On 15-10-02 04:50 PM, Bardur Arantsson wrote:
On 10/02/2015 12:09 PM, Henrik Nilsson wrote:
Hi all,
[--snip--]
So from that perspective, using the applicative operators directly, without any syntactic sugar, actually amounts to a much more transparent and honest syntax, even if a bit more verbose in some cases.
"Verbose" is the understatement of the year. There's a lot of code where ApplicativeDo makes the difference between "readable" and "unreadable". Like it or not, but programmers are used to *naming things* (even locally) and using those local names to refer to things.
Naming of applicative sub-expressions is perfectly doable without reaching for any syntactic sugar. An applicative do like do a <- f long expression b <- g long expression return (h a b) would be equivalent to let a = f long expression b = g long expression in f <$> a <*> b The benefits of applicative do, if I understand the motivation correctly, are not so much to help in writing new code intended to be applicative. Instead it lets the programmer write in monadic style and at the same time enables the compiler to convert the code to applicative style if possible. This has the potential to automatically improve performance of legacy Haskell codebase, as well as any new beginner-friendly code that relies on syntactic sugar. As for the issue of textbooks, I assume they describe Haskell 98. Until Haskell compilers start defaulting to Haskell 2020 there shouldn't be any issue.

On 10/02/2015 11:55 PM, Mario Blažević wrote:
On 15-10-02 04:50 PM, Bardur Arantsson wrote:
On 10/02/2015 12:09 PM, Henrik Nilsson wrote:
Hi all,
[--snip--]
So from that perspective, using the applicative operators directly, without any syntactic sugar, actually amounts to a much more transparent and honest syntax, even if a bit more verbose in some cases.
"Verbose" is the understatement of the year. There's a lot of code where ApplicativeDo makes the difference between "readable" and "unreadable". Like it or not, but programmers are used to *naming things* (even locally) and using those local names to refer to things.
Naming of applicative sub-expressions is perfectly doable without reaching for any syntactic sugar. An applicative do like
do a <- f long expression b <- g long expression return (h a b)
would be equivalent to
let a = f long expression b = g long expression in f <$> a <*> b
The benefits of applicative do, if I understand the motivation correctly, are not so much to help in writing new code intended to be applicative. Instead it lets the programmer write in monadic style and at the same time enables the compiler to convert the code to applicative style if possible. This has the potential to automatically improve performance of legacy Haskell codebase, as well as any new beginner-friendly code that relies on syntactic sugar.
... if you already know how to do that. That's the point. Regards,

On Fri, Oct 2, 2015 at 2:55 PM, Mario Blažević
"Verbose" is the understatement of the year. There's a lot of code where ApplicativeDo makes the difference between "readable" and "unreadable". Like it or not, but programmers are used to *naming things* (even locally) and using those local names to refer to things.
Naming of applicative sub-expressions is perfectly doable without reaching for any syntactic sugar. An applicative do like
Isn't the debate about 'return', not about ApplicativeDo? ApplicativeDo is already in the next version, so I think it's been decided.

On Fri, 2 Oct 2015, Mario Blažević wrote:
The benefits of applicative do, if I understand the motivation correctly, are not so much to help in writing new code intended to be applicative. Instead it lets the programmer write in monadic style and at the same time enables the compiler to convert the code to applicative style if possible. This has the potential to automatically improve performance of legacy Haskell codebase, as well as any new beginner-friendly code that relies on syntactic sugar.
I see the benefit of ApplicativeDo in the short distance of the value producer and the value naming. E.g. compare liftA3 (\x y z -> complicatedFunc x y z) produceX produceY produceZ and do x <- produceX y <- produceY z <- produceZ pure $ complicatedFunc x y z Using the first style you may easily introduce inconsistencies if you change the order of produceX, produceY, produceZ, whereas with the second style you will certainly change whole lines and stay consistent this way.

On 19 Oct 2015, at 20:52, Henning Thielemann
I see the benefit of ApplicativeDo in the short distance of the value producer and the value naming. E.g. compare
liftA3 (\x y z -> complicatedFunc x y z) produceX produceY produceZ
and
do x <- produceX y <- produceY z <- produceZ pure $ complicatedFunc x y z
Agreed. Furthermore I quite like the way applicative comprehensions read: [complicatedFunc x y z | x <- produceX, y <- produceY, z <- produceZ ] Also, what this example doesn’t show is that sometimes complicatedFunc is actually a complicated *expression* which merely mentions x,y,z each 1 or more times: [ . . . some long code mentioning x . . . . . . and y and x again and now z . . . | x <- produceX, y <- produceY, z <- produceZ ] As Henning says the tradeoffs here are all to do with drawing the eye correctly between the use of x,y,z and the binding of x y x. There is also the fact that x y and z may not ‘naturally’ occur in the right order - the ordering of effects in the producers can easily be significant. Jules

Hi all, Bardur Arantsson wrote:
I should also say: I certainly *understand* the textbook argument, [...] but this is not a good *general* argument against change.
Just to be clear, Graham and I were not at all arguing against change in general. But we are, in general, urging extreme caution when it comes to non-essential breaking changes. Measuring breakage by referring to Hackage is just the tip of the iceberg. Much breakage, including proprietary code, books, research papers, what people have learned, is very difficult or impossible to measure. Somehow this point seems to have been forgotten in the present discussion. The reason there has to be really compelling reasons for adopting breaking changes is exactly because the full impact of those breaking changes is very hard to gauge properly. As to this specific proposal, in our opinion, the reasons put forward so far for the "monad of no return" are not very compelling. And therefore it should not be adopted at this point.
Have you surveyed the actual number of books out there which show how to implement Monad instances and how many of them would be affected?
No. we have not. But ought not the burden of proof rest with those who are proposing a non-essential breaking change? If not, why not?
but if we're going that way, then we're going to end up like C++... before C++11/C++14. [...] (stagnatiation)
We are hardly going to end up like C++ in that sense by being very careful before adopting non-essential breaking changes. Or even rule them out. Nor, returning to this specific proposal, is leaving "return" as a method of "Monad" going to mean that Haskell ends up being stagnant. Further, it is also worth noting that by almost any measure C++ is an extremely successful language despite its warts.
"Verbose" is the understatement of the year. There's a lot of code where ApplicativeDo makes the difference between "readable" and "unreadable". Like it or not, but programmers are used to *naming things* (even locally) and using those local names to refer to things.
If so, suggesting that programmers necessarily want to name things is the sweeping generalisation of the year. For example, I have written quite a bit of applicative code, way before it was even called applicative, and I did not find the lack of syntactic support particularly bothersome. On the other hand, I have also written a lot of arrowized code, and there, while I do use the syntactic sugar to allow me to name certain things, the fact that I then have to name everything is rather annoying to say the least, and I have often found myself wishing that I could write arrowized code that looked a lot more like applicative code (without the sugar). For a very different example, function composition, maps, and folds are all examples of constructs in common use where programmers opt to not name intermediate things. Anyway, a discussion about the pros and cons of applicative do entitrely tangential to the point being made. The point is that applicative do is not yet part of any Haskell standard, and at this point it is not clear what any future syntactic support for applicative code will look like exactly. Therefore is premature to use this as an argument for this particular proposal, making any such an argument a weak one. Removal of "return" as a method of Monad can clearly wait until such time that syntactic support for applicative code makes it into the language, if it then is found that that support, whatever it looks like, would be unworkable without this change. Further, I reiterate that if people writing applicative code were to use "pure" instead of "return", which does not at all seem unreasonable, the stated problem goes away. And such a change would clearly have far less impact on legacy code, text books, teaching material, what many programmers have learned simply by virtue of the fact that Applicative in its current form is a very recent addition. Bottom line: Breaking changes should only be adopted for very compelling reasons. The reasons put forward for far for "monad of no return" fails to meet that standard. Therefore it should not be adopted, at least not at this time. /Henrik -- Henrik Nilsson School of Computer Science The University of Nottingham nhn@cs.nott.ac.uk This message and any attachment are intended solely for the addressee and may contain confidential information. If you have received this message in error, please send it back to me, and immediately delete it. Please do not use, copy or disclose the information contained in this message or in any attachment. Any views or opinions expressed by the author of this email do not necessarily reflect the views of the University of Nottingham. This message has been checked for viruses but the contents of an attachment may still contain software viruses which could damage your computer system, you are advised to perform your own checks. Email communications with the University of Nottingham may be monitored as permitted by UK legislation.

On Fri, Oct 2, 2015 at 8:31 PM, Henrik Nilsson
Further, it is also worth noting that by almost any measure C++ is an extremely successful language despite its warts.
Ah, success at the cost of warts. I see our priorities as a community have changed.
Anyway, a discussion about the pros and cons of applicative do entitrely tangential to the point being made. The point is that applicative do is not yet part of any Haskell standard, and at this point it is not clear what any future syntactic support for applicative code will look like exactly. Therefore is premature to use this as an argument for this particular proposal, making any such an argument a weak one. Removal of "return" as a method of Monad can clearly wait until such time that syntactic support for applicative code makes it into the language, if it then is found that that support, whatever it looks like, would be unworkable without this change.
…
Bottom line: Breaking changes should only be adopted for very compelling reasons. The reasons put forward for far for "monad of no return" fails to meet that standard. Therefore it should not be adopted, at least not at this time.
`return` should have never been a part of the `Monad` type class. It does not belong there any more than `fail` does. We could discuss (in a separate thread) whether `pure` should be named `return`. We could likewise discuss whether it should be in some separate class like the often-suggested `Point` with whatever name. We could likewise discuss where that class should lie in the hierarchy. In a post-AMP Haskell, however, retaining `return` in `Monad` does not serve any purpose: any `Monad` instance requires an `Applicative` instance, wherein `pure` must be defined, and it is a law required by all instances that they behave identically. The only expressive purpose of `return` being in the `Monad` type class is providing an opportunity to break the laws the community expects for all instances of `Monad`. This community rightly values statically eliminating opportunities for errors, and the removal of `return` as a method of `Monad` serves this purpose. This is reason alone to implement this proposal, even in the absence of `ApplicativeDo`.

Hi all, Manuel Gómez wrote:
Further, it is also worth noting that by almost any measure C++ is an extremely successful language despite its warts.
Ah, success at the cost of warts. I see our priorities as a community have changed.
That's nonsensical and unnecessarily polemic. I am merely pointing out that removal of every single "wart" is not a prerequisite for success. But striving for "perfection" can have significant and even unjustifiable costs.
`return` should have never been a part of the `Monad` type class.
That's an odd statement. The mathematical concept of a monad clearly does not necessitate structuring things as a hierarchy of classes. In any case, the point is that "return" has been part of "Monad" for some 25 years. That's a serious historical legacy that should not be dismissed lightly for reasons already discussed.
In a post-AMP Haskell, however, retaining `return` in `Monad` does not serve any purpose:
That is not true. It does provide for an opportunity to write code that works with versions of GHC prior to 7.10 as well as later versions with a few fairly small fixes and (without resorting to conditional compilation). That's important to some people.
This community rightly values statically eliminating opportunities for errors, and the removal of `return` as a method of `Monad` serves this purpose. This is reason alone to implement this proposal, even in the absence of `ApplicativeDo`.
While I do accept your point about a mostly redundant "return" providing one opportunity to accidentally breaking a law that should hold, *any* Monad instance provide an opportunity for breaking multiple laws. Further, there are a range of classes where there are methods with default instances that are there to provide for an opportunity for more efficient implementation. They also need to satisfy laws and again there is an opportunity for accidentally breaking those. I am thus hard pressed to believe that keeping "return" as a method makes of Monad makes any perceptible practical difference either way in that respect. So, at least in my opinion, this is argument is no stronger than those already put forward. All the best, /Henrik -- Henrik Nilsson School of Computer Science The University of Nottingham nhn@cs.nott.ac.uk This message and any attachment are intended solely for the addressee and may contain confidential information. If you have received this message in error, please send it back to me, and immediately delete it. Please do not use, copy or disclose the information contained in this message or in any attachment. Any views or opinions expressed by the author of this email do not necessarily reflect the views of the University of Nottingham. This message has been checked for viruses but the contents of an attachment may still contain software viruses which could damage your computer system, you are advised to perform your own checks. Email communications with the University of Nottingham may be monitored as permitted by UK legislation.

On Fri, 2 Oct 2015, Manuel Gómez wrote:
In a post-AMP Haskell, however, retaining `return` in `Monad` does not serve any purpose: any `Monad` instance requires an `Applicative` instance, wherein `pure` must be defined, and it is a law required by all instances that they behave identically. The only expressive purpose of `return` being in the `Monad` type class is providing an opportunity to break the laws the community expects for all instances of `Monad`.
We will get constant breakage this way. You mentioned Pointed class. If it appears one day then your argument would translate to: We must acknowledge that 'pure' was always wrong in Applicative. Then we will have an APP (Applicative without 'pure' proposal) that again breaks lots of code without a way to code for multiple versions of base.

I take your concerns about unnecessary breaking changes seriously. And it
is certainly true that a large amount of existing code will break. However,
I am not at all convinced that the "mental weight" of this change is nearly
as great as that of the now-accomplished AMP, in the presence of good error
messages. Someone reading a classic article on Haskell who writes out their
Monad instance will already be informed that they need to first cough up an
instance of a class that article has no information about. An additional
error message telling them to please delete a single binding hardly seems
onerous in comparison.
I think removing error-prone redundancy is a good thing. While I expect
there are few return/pure mismatches, they are certainly possible. The most
likely scenario, I imagine, involves a difference in strictness when
someone erroneously thinks they can get away with
Applicative f => Applicative (t f)
when in fact they need
Monad f => Applicative (t f)
to obey pure = return in that particular case.
On Oct 2, 2015 9:01 PM, "Henrik Nilsson"
Hi all,
Bardur Arantsson wrote:
I should also say: I certainly *understand* the textbook argument, [...] but this is not a good *general* argument against change.
Just to be clear, Graham and I were not at all arguing against change in general. But we are, in general, urging extreme caution when it comes to non-essential breaking changes.
Measuring breakage by referring to Hackage is just the tip of the iceberg. Much breakage, including proprietary code, books, research papers, what people have learned, is very difficult or impossible to measure. Somehow this point seems to have been forgotten in the present discussion. The reason there has to be really compelling reasons for adopting breaking changes is exactly because the full impact of those breaking changes is very hard to gauge properly. As to this specific proposal, in our opinion, the reasons put forward so far for the "monad of no return" are not very compelling. And therefore it should not be adopted at this point.
Have you surveyed the actual number of books out there which show how to implement Monad instances and how many of them would be affected?
No. we have not. But ought not the burden of proof rest with those who are proposing a non-essential breaking change? If not, why not?
but if we're going that way, then we're going to end up like C++... before C++11/C++14. [...] (stagnatiation)
We are hardly going to end up like C++ in that sense by being very careful before adopting non-essential breaking changes. Or even rule them out. Nor, returning to this specific proposal, is leaving "return" as a method of "Monad" going to mean that Haskell ends up being stagnant.
Further, it is also worth noting that by almost any measure C++ is an extremely successful language despite its warts.
"Verbose" is the understatement of the year. There's a lot of code where ApplicativeDo makes the difference between "readable" and "unreadable". Like it or not, but programmers are used to *naming things* (even locally) and using those local names to refer to things.
If so, suggesting that programmers necessarily want to name things is the sweeping generalisation of the year.
For example, I have written quite a bit of applicative code, way before it was even called applicative, and I did not find the lack of syntactic support particularly bothersome. On the other hand, I have also written a lot of arrowized code, and there, while I do use the syntactic sugar to allow me to name certain things, the fact that I then have to name everything is rather annoying to say the least, and I have often found myself wishing that I could write arrowized code that looked a lot more like applicative code (without the sugar).
For a very different example, function composition, maps, and folds are all examples of constructs in common use where programmers opt to not name intermediate things.
Anyway, a discussion about the pros and cons of applicative do entitrely tangential to the point being made. The point is that applicative do is not yet part of any Haskell standard, and at this point it is not clear what any future syntactic support for applicative code will look like exactly. Therefore is premature to use this as an argument for this particular proposal, making any such an argument a weak one. Removal of "return" as a method of Monad can clearly wait until such time that syntactic support for applicative code makes it into the language, if it then is found that that support, whatever it looks like, would be unworkable without this change.
Further, I reiterate that if people writing applicative code were to use "pure" instead of "return", which does not at all seem unreasonable, the stated problem goes away. And such a change would clearly have far less impact on legacy code, text books, teaching material, what many programmers have learned simply by virtue of the fact that Applicative in its current form is a very recent addition.
Bottom line: Breaking changes should only be adopted for very compelling reasons. The reasons put forward for far for "monad of no return" fails to meet that standard. Therefore it should not be adopted, at least not at this time.
/Henrik
-- Henrik Nilsson School of Computer Science The University of Nottingham nhn@cs.nott.ac.uk
This message and any attachment are intended solely for the addressee and may contain confidential information. If you have received this message in error, please send it back to me, and immediately delete it. Please do not use, copy or disclose the information contained in this message or in any attachment. Any views or opinions expressed by the author of this email do not necessarily reflect the views of the University of Nottingham.
This message has been checked for viruses but the contents of an attachment may still contain software viruses which could damage your computer system, you are advised to perform your own checks. Email communications with the University of Nottingham may be monitored as permitted by UK legislation.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Hi all, David Feuer wrote:
I take your concerns about unnecessary breaking changes seriously. And it is certainly true that a large amount of existing code will break. However, I am not at all convinced that the "mental weight" of this change is nearly as great as that of the now-accomplished AMP, in the presence of good error messages.
That may be true (and if pressed, I'd likely agree with you), but it is beside the Graham and I were making: AMP does not necessitate "monad of no return", and the cost of the additional breakage of the latter should thus be justified in terms of how essential it is for other reasons. At least there should be a very compelling argument that the advantages clearly outweighs the costs. And again, in any case like this, I think the burden of proof necessarily rests with those who are arguing for the change.
I think removing error-prone redundancy is a good thing.
Undeniably. But does eliminating this particular redundancy make enough of a practical difference to justify the costs? There are plenty of opportunities to break laws and introducing strictness bugs anyway. See previous e-mail. All the best, /Henrik -- Henrik Nilsson School of Computer Science The University of Nottingham nhn@cs.nott.ac.uk This message and any attachment are intended solely for the addressee and may contain confidential information. If you have received this message in error, please send it back to me, and immediately delete it. Please do not use, copy or disclose the information contained in this message or in any attachment. Any views or opinions expressed by the author of this email do not necessarily reflect the views of the University of Nottingham. This message has been checked for viruses but the contents of an attachment may still contain software viruses which could damage your computer system, you are advised to perform your own checks. Email communications with the University of Nottingham may be monitored as permitted by UK legislation.

On 10/03/2015 03:01 AM, Henrik Nilsson wrote:
Hi all,
Bardur Arantsson wrote:
I should also say: I certainly *understand* the textbook argument, [...] but this is not a good *general* argument against change.
Just to be clear, Graham and I were not at all arguing against change in general. But we are, in general, urging extreme caution when it comes to non-essential breaking changes.
Measuring breakage by referring to Hackage is just the tip of the iceberg. Much breakage, including proprietary code, books, research papers, what people have learned, is very difficult or impossible to measure. Somehow this point seems to have been forgotten in the present discussion. The reason there has to be really compelling reasons for adopting breaking changes is exactly because the full impact of those breaking changes is very hard to gauge properly. As to this specific proposal, in our opinion, the reasons put forward so far for the "monad of no return" are not very compelling. And therefore it should not be adopted at this point.
Have you surveyed the actual number of books out there which show how to implement Monad instances and how many of them would be affected?
No. we have not. But ought not the burden of proof rest with those who are proposing a non-essential breaking change? If not, why not?
but if we're going that way, then we're going to end up like C++... before C++11/C++14. [...] (stagnatiation)
We are hardly going to end up like C++ in that sense by being very careful before adopting non-essential breaking changes. Or even rule them out. Nor, returning to this specific proposal, is leaving "return" as a method of "Monad" going to mean that Haskell ends up being stagnant.
Further, it is also worth noting that by almost any measure C++ is an extremely successful language despite its warts.
C++ is what "success at all cost" looks like. (I won't bother responding to the rest, others have done that adequately.) Look, I truly[1] do appreciate the arguments in favor of "don't break things", but I don't think it's borne out by any reasonable reading of history. Regards, [1] At least I think I do. :)

Hi all, Bardur Arantsson wrote: On 10/03/2015 10:06 AM, Bardur Arantsson wrote:
C++ is what "success at all cost" looks like. (I won't bother responding to the rest, others have done that adequately.)
Haskell is at no risk of becoming like C++ in that respect either. The point being made was just that the odd wart is not a big problem. But breaking things without really compelling reasons is.
Look, I truly[1] do appreciate the arguments in favor of "don't break things", but I don't think it's borne out by any reasonable reading of history.
Again, Graham and I were not saying "don't break things". We were saying "if things are to be broken, then there had better be very compelling reasons". That's a big difference. Best, /Henrik -- Henrik Nilsson School of Computer Science The University of Nottingham nhn@cs.nott.ac.uk This message and any attachment are intended solely for the addressee and may contain confidential information. If you have received this message in error, please send it back to me, and immediately delete it. Please do not use, copy or disclose the information contained in this message or in any attachment. Any views or opinions expressed by the author of this email do not necessarily reflect the views of the University of Nottingham. This message has been checked for viruses but the contents of an attachment may still contain software viruses which could damage your computer system, you are advised to perform your own checks. Email communications with the University of Nottingham may be monitored as permitted by UK legislation.

Henrik Nilsson
writes:
Again, Graham and I were not saying "don't break things". We were saying "if things are to be broken, then there had better be very compelling reasons".
That's a big difference.
You made a great argument, Henrik, and you've changed my enthusiastic +1 to +0, until it can be bundled with some other, more necessary, breaking change. John

John Wiegley wrote:
You made a great argument, Henrik, and you've changed my enthusiastic +1 to +0, until it can be bundled with some other, more necessary, breaking change.
I, too, am hereby changing my +1 to a 0. (Even though John himself eventually went back to +1.) I am one of the people who would eventually pay a steep price for this change. I voted +1 only because there seemed to be a clear consensus to do it. I intended to express with my vote that I am willing to pay that price if there is such a consensus. But since then, quite a few very prominent members of the community have come out strongly against this change. So I am now climbing back onto the fence, which is where I will sit until/unless a consensus one way or the other develops again. -Yitz

On 2015-10-03 at 03:01:12 +0200, Henrik Nilsson wrote: [...]
Have you surveyed the actual number of books out there which show how to implement Monad instances and how many of them would be affected?
No. we have not. But ought not the burden of proof rest with those who are proposing a non-essential breaking change? If not, why not?
Well, afaik the books commonly used in teaching are largely based on Haskell 98 or Haskell 2010. ( IMO, the problem here is rather the expectation that the latest GHC would still provide a Haskell 2010 library environment, even though the few books based on GHC for the most part let the reader run GHC in default mode and mention neither `-XHaskell2010` nor `-package haskell2010`. And yes, GHC 7.10 effectively had to drop support for `-package haskell2010`. Otoh, There's several Linux distributions still stuck on GHC 7.6.3 (e.g. Debian & Ubuntu) or even older. Btw, would the concern be addressed if a future GHC would recover a legacy Haskell2010 library environment? ) All books I've looked at so far will undoubtedly have their examples defining `Monad` instances be broken under the next Haskell Report, even *without* the MRP which simplifies the Haskell Report and is surely more desirable from a pedagogical point of view as well. ---------------------------------------------------------------------------- For instance, in Graham Hutton's Book the section about defining Monad instances in chapter 10[1] is rather short (defining `Monad` instances is not an essential part of that book) and presents the Monads type-class literally as class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b and goes on to claim | Using this declaration, parsers and interactive programs can then be | made into instances of the class of monadic types, by defining the two | member functions in the appropriate manner: And this will clearly not apply anymore under the next Haskell Report. On the bright side, `fail` is not mentioned, so at least it won't break under the MonadFail change. ---- Richard Bird's "Thinking Functionally with Haskell" from 2014 sticks to Haskell2010, and presents the `Monad` class exactly like Graham's book (i.e. providing only `return` and `(>>=)`). Curiously, even though published in 2014, `Applicative` isn't mentioned anywhere in the book. In any case, this Book's `Monad`-instance examples will be broken as well under a new Haskell Report due to the AMP change. ---- Simon Thompson's "Haskell - the Craft of Functional Programming, 3ed" (2011), on the other hand presents the `Monad` class exactly as written into the Haskell 2010 Report, namely: class Monad m where (>>=) :: m a -> (a -> m b) -> m b return :: a -> m a (>>) :: m a -> m b -> m b fail :: String -> m a m >> k = m >>= \_ -> k fail s = error s Consequently, `Monad`-defining examples in that book break on accounts of both, AMP *and* MonadFail changes. ---- The "Real World Haskell" book predates Haskell 2010 by a few years but features the `Applicative` class. `Monad`-instance examples contained in the book break on accounts of AMP and MonadFail as well. ---- Miran Lipovaca's very popular "Learn You a Haskell for Great Good" (2011) book is written in a more casual style and targets mostly Haskell 2010. The `Monad` class is presented with the 4 methods according to the Haskell 2010 Report.[2] The `Applicative` class is mentioned and the missing superclass relationship is pointed out: | Shouldn't there be a class constraint in there along the lines of | `class (Applicative m) => Monad m where` so that a type has to be an | applicative functor first before it can be made a monad? Well, there | should, but when Haskell was made, it hadn't occured to people that | applicative functors are a good fit for Haskell so they weren't in | there. It's also noteworthy that the book has to explain why there are two different verbs for the same purpose: | The first function that the Monad type class defines is `return`. It's | the same as `pure`, only with a different name. Its type is `(Monad m) | => a -> m a`. It takes a value and puts it in a minimal default | context that still holds that value. In other words, it takes | something and wraps it in a monad. It always does the same thing as | the `pure` function from the `Applicative` type class, which means | we're already acquainted with `return`. We already used `return` when | doing I/O. We used it to take a value and make a bogus I/O action that | does nothing but yield that value. The `MonadFail` class, however, is neither mentioned nor anticipated. So LYAH will need to be updated as well regarding AMP and MonadFail induced breakages. ---- Finally, Alejandro Serrano Mena's more practical "Beginning Haskell" book also provides to the full Haskell 2010 `Monad` class definition. The `Applicative` class is described as well. However, the book was clearly written in the knowledge of the upcoming AMP: | If any Monad instance is also an instance of Functor, why is this | relation not shown in the declaration of those classes? This is a | historical accident, and you should expect Functor to soon become a | superclass of Monad . In the meantime, you should ensure that you have | an instance of Functor for each of your Monad instances: you can build | one easily using the aforementioned liftM function. as well as | The fact that Applicative does not appear as a superclass of Monad is | again a historical accident: the Monad concept was used widely much | earlier than the concept of Applicative . For compatibility reasons, | Monad hasn’t changed its definition to include any of Functor or | Applicative as superclasses. This will change soon, though, and the | full hierarchy Functor , then Applicative , then Monad will be | apparent in the type classes. But at the time of writing the MonadFail proposal couldn't be foreseen. ---------------------------------------------------------------------------- These may not be all the Haskell books out there, but these examples clearly show that we've already set a precedent with the AMP and the MonadFail proposal alone. There are a few other base-library transitions already happened or in mid-flight that have a similar effect on published books and materials which leave the boundaries of the Haskell 2010 Library Report. So if the primary argument is that published literature shouldn't get broken. Well, that's already happened. And there will unavoidably be incompatible changes between Haskell2010 and Haskell201x. The point of this Monad-of-no-return Proposal was to provide the formal basis to be able to write the AMP into the next upcoming Haskell Report in a sensible way (and I think we can all agree that this is the right thing to do as there is no good justification for including the `Monad(return)`-method in an Haskell Report integrating the AMP changes) However, one thing that seems to have been mostly ignored in this whole discussion so far is that just because the next Haskell Report anticipates the removal of `return` and `(>>)` as methods this doesn't mean that GHC's `base` library has to follow suit immediately! The proposal states that phase 2 can happen in GHC 8.2 *or later*. This could also mean e.g. GHC 8.4, GHC 8.8, or even GHC 9.0! This is very different from the AMP, MFP or FTP which are/were subject to a swift transition scheme with a rigid timeframe. Old code still overriding `return` will continue to compile (if it didn't break already for AMP/MFP/...) for as many years in GHC as desired. And code written against the new Haskell Report (especially when ignoring the existence of the `return`-method) would work just fine against GHC's `base` as well. So there's not that much immediate breakage due to MRP specifically after all. Regards, H.V.Riedel [1]: http://i.imgur.com/DyPTZml.png [2]: http://learnyouahaskell.com/a-fistful-of-monads#the-monad-type-class

Herbert Valerio Riedel
writes:
The point of this Monad-of-no-return Proposal was to provide the formal basis to be able to write the AMP into the next upcoming Haskell Report in a sensible way (and I think we can all agree that this is the right thing to do as there is no good justification for including the `Monad(return)`-method in an Haskell Report integrating the AMP changes)
However, one thing that seems to have been mostly ignored in this whole discussion so far is that just because the next Haskell Report anticipates the removal of `return` and `(>>)` as methods this doesn't mean that GHC's `base` library has to follow suit immediately!
The proposal states that phase 2 can happen in GHC 8.2 *or later*. This could also mean e.g. GHC 8.4, GHC 8.8, or even GHC 9.0! This is very different from the AMP, MFP or FTP which are/were subject to a swift transition scheme with a rigid timeframe.
Old code still overriding `return` will continue to compile (if it didn't break already for AMP/MFP/...) for as many years in GHC as desired.
And code written against the new Haskell Report (especially when ignoring the existence of the `return`-method) would work just fine against GHC's `base` as well.
So there's not that much immediate breakage due to MRP specifically after all.
Then count me again as +1, thanks for the clarification, Herbert. John

On Sat, 3 Oct 2015, Henrik Nilsson wrote:
For example, I have written quite a bit of applicative code, way before it was even called applicative, and I did not find the lack of syntactic support particularly bothersome. On the other hand, I have also written a lot of arrowized code, and there, while I do use the syntactic sugar to allow me to name certain things, the fact that I then have to name everything is rather annoying to say the least, and I have often found myself wishing that I could write arrowized code that looked a lot more like applicative code (without the sugar).
I was unhappy about arrow syntax for the same reasons and with Mr. Apfelmus I developed a technique that allows to apply Arrows in an Applicative style. However, because it relies on the Vault data structure it works efficiently only for EDSL things. Unfortunately we have not written up the method so far, I have only a complicated module that employs the method: https://hackage.haskell.org/package/synthesizer-llvm-0.7.0.1/src/src/Synthes... If I find time I could extract the according code to a new package.

I am also a strong -1 on small changes that break huge numbers of things for somewhat trivial benefits. Regards, Malcolm On 2 Oct 2015, at 11:09, Henrik Nilsson wrote:
Hi all,
I have discussed the monad of no return proposal with my colleague Graham Hutton: a long-standing member of the Haskell community, well-known researcher, some 20 years of experience of teaching Haskell to undergraduate students, and author of one of the most successful introductory Haskell textbooks there are.
The upshot of this e-mail is a strong collective -2 from us both on particular proposal, and a general call for much more caution when it comes to breaking changes that are not critically important.
First, on a general note, there has recently been a flurry of breaking changes to the (de facto) Haskell standards. In many cases for very good reasons, but sometimes it seems more in a quest for perfection without due consideration for the consequences. It used to be the case that breaking changes were very rare indeed. And for good reason.
Right now, the main "measure of breakage" in the on-line discussions seems to be how many packages that break in Hackage. Which of course makes sense: the Hackage repository is very important and such a measure is objective, as far as it goes.
But we should not forget that breakage can go far beyond Hackage. For starters, there is *lots* of code that is not in Hackage, yet critically important to its users, however many or few they are. There are more than hundreds of thousands of copies of books out there where that may break in that examples may no longer work. And they cannot be changed. There are countless research papers that may break in the same way. Every single institution that use Haskell in their teaching may have to update their teaching materials (slides, code, lab instructions) for every module that teaches or uses Haskell. And last but not the least, what countless of programmers and students have learned about Haskell over decades, most of whom are *not* power users who can take these changes in their stride, may also break.
Now, of course a language has to evolve, and sometimes breaking backwards compatibility is more or less essential for the long-term benefit of the language. But we should not let perfection be the enemy of the good.
As to this particular proposal, the monad of no return, it does not seem essential to us, but mostly motivated by a quest for "perfection" as defined by a very knowledgeable but in relative terms small group of people.
One argument put forward was that applicative code that uses "return" instead of "pure" should get a less constrained type. But such code is relatively new. The methods of the Monad class have been return and bind for some 25 years. So indeed, as Henning Thielemann wrote: why should not the newer code be adapted and use "pure" instead? In fact, the use of "pure" in such code could serve as a quite useful cue that the code is applicative rather than monadic, especially where applicative do is employed.
Another reason put forward is support for the applicative do syntax. But that is, in standard terms, only a future possibility at this point. Further, the syntax is arguably rather dubious anyway as it, in particular to someone with an imperative background, suggests a sequential reading which is exactly what applicative is not and why it is useful. So from that perspective, using the applicative operators directly, without any syntactic sugar, actually amounts to a much more transparent and honest syntax, even if a bit more verbose in some cases.
The bottom line is that it is premature to put forward support for the applicative do syntax as a rationale for a non-essential breaking change.
Best regards,
Henrik Nilsson and Graham Hutton
-- Henrik Nilsson School of Computer Science The University of Nottingham nhn@cs.nott.ac.uk

On 24.09 23:43, Herbert Valerio Riedel wrote:
Concluding AMP and MFP, We (David and I) proudly present you the final installment of the Monad trilogy:
-1 Would providing automated tooling for changes be possible? I think there would be much less resistance if there was working automatic tooling for the various changes and e.g. >95% of Hackage would build with each new GHC version. Currently code seems to be breaking with every major GHC release. In essence this drives up costs of maintaining software. One of the reasons I use Haskell less than I used to use for work stuff is the lack of stability and constant breakage that adds up. - Taru Karttunen

Herbert Valerio Riedel
Hello *,
Concluding AMP and MFP, We (David and I) proudly present you the final installment of the Monad trilogy:
Monad of no `return` Proposal =============================
TLDR: To complete the AMP, turn `Monad(return)` method into a top-level binding aliasing `Applicative(pure)`.
+1 With a sufficiently long timeframe for adoption (with removal no earlier than 8.4) it seems like the immediate cost of this change shouldn't be so onerous; if we managed AMP then we should be able to pull this off as well. It seems to be the right thing to do and I sincerely believe we can keep the cost to users low; let's do it. I find this especially true in light of the recent advances made in the area of tooling. We are now in a much better position to be offering tools for automated refactoring than we were even when we considered AMP. Perhaps one of the HaRe contributors can comment on the feasibility of automatically rewriting `return` definitions to `pure` definitions? It feels like this should be quite workable in most cases. It also helps that we have the luxury of being able to pick this change up at a relaxed pace. For a long time, we as a community have lamented the lack of tools (both language features and otherwise) for restructuring typeclass hierarchies (e.g. see #4879, #2119, #10071). Since we now have the experience of AMP under our collective belts, it seems like we are in a much better position to put forward some concrete proposals for easing this sort of interface refactoring and deprecation. The `DEPRECATED`/`REMOVED` pragmas on class methods would be a great step towards this end. With a bit of work we could greatly reduce the impact of changes like these; an improvement that could bring benefits well beyond the core libraries. Those interested in contributing in this area should see the Wiki [1]. With respect to invalidating teaching materials, I think this ship has already sailed with AMP and `MonadFail`, as Herbert has pointed out. Nevertheless we can help their users evolve along with the language with deprecation mechanisms, tools, and approachable error messages. Cheers, - Ben [1] https://ghc.haskell.org/trac/ghc/wiki/Design/DeprecationMechanisms

1) I would like to ban the usage of the term "C++" in all libraries mailing list discussions except for those discussing binding C++ code. I have never seen intelligent discussion result from bringing up "C++" in an unrelated context. 2) Is there an updated wiki page for this proposal that explains the migration path for the community It seems that there is a lot of discussion about what this proposal might be and it is time to make it more concrete (particularly with respect to how exactly library and application authors handle breakage) if there is going to be more productive conversation going forward. Also, one should not be required to re-read this long thread and pick out important details to understand the proposal as it exists now.

I find this especially true in light of the recent advances made in the area of tooling. We are now in a much better position to be offering tools for automated refactoring than we were even when we considered AMP.
Well, it's not like this particular proposal requires tools any more sophisticated than cut&paste (for instance declarations) and search&replace (/return/pure/). The only code that will be negatively affected is code that is not maintained or is printed on dead trees. Best regards, Marcin Mrotek

Strong +1
this needs to happen.
I'm ok with the migration overhead, and nows a good time to clean up these
core things now that we understand what they should be / how they're
interrelated. Most of the concerns i've seen seem to be a rehash of those
from AMP and friends, which worked out pretty well I think!
cheers!
On Thu, Sep 24, 2015 at 5:43 PM, Herbert Valerio Riedel
Hello *,
Concluding AMP and MFP, We (David and I) proudly present you the final installment of the Monad trilogy:
Monad of no `return` Proposal =============================
TLDR: To complete the AMP, turn `Monad(return)` method into a top-level binding aliasing `Applicative(pure)`.
Current Situation -----------------
With the implementation of Functor-Applicative-Monad Proposal (AMP)[1] and (at some point) the MonadFail proposal (MFP)[2] the AMP class hierarchy becomes
class Functor f where fmap :: (a -> b) -> f a -> f b
class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b u *> v = …
(<*) :: f a -> f b -> f a u <* v = …
class Applicative m => Monad m where (>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a return = pure
(>>) :: m a -> m b -> m b m >> k = …
class Monad m => MonadFail m where fail :: String -> m a
Consequently, the `Monad` class is left with a now redundant `return` method as a historic artifact, as there's no compelling reason to have `pure` and `return` implemented differently.
Traditionally, `return` is often used where `pure` would suffice today, forcing a `Monad` constraint even if a weaker `Applicative` would have sufficed.
As a result, language extensions like `ApplicativeDo`[3] have to rewrite `return` to weaken its `Monad m =>` constraint to `Applicative m =>` in order to benefit existing code at the cost of introducing magic behavior at the type level.
Finally, this redundancy becomes even more significant when viewed in light of the renewed Haskell standardisation process[7]: The next Haskell Report will almost certainly incorporate the AMP (and MFP) changes, and there's no justification for the Report to retain `return` as a method of `Monad`. A good reason would have been to retain backward compatibility with Haskell 2010. However, as the AMP superclass hierarchy requires `Monad` instances to be accompanied by `Applicative` instances (which aren't part of Haskell 2010, c.f. [6]), backward compatibility with Haskell 2010 goes out the window when it comes to defining `Monad` instances (unless via use of `-XCPP` or similar). Consequently, meeting the high bar for a formal document such as the Haskell Report demands that `Monad` shall not carry a redundant `return` method that serves no purpose anymore. Moreover, getting `return` out of the way is desirable to facilitate standardising potential candidates such as the earlier mentioned `ApplicativeDo` in the future and avoids the technical debt incurred by keeping around this language wart.
Proposed Change ---------------
Remove `return` as a method from the `Monad` class and in its place define a top-level binding with the weaker `Applicative` typeclass constraint:
-- | Legacy alias for 'pure' return :: Applicative f => a -> f a return = pure
This allows existing code using `return` to benefit from a weaker typeclass constraint as well as cleaning the `Monad` class from a redundant method in the post-AMP world.
A possible migration strategy is described further below.
Compatibility Considerations ----------------------------
Generalizing the type signature of a function from a `Monad` constraint to its superclass `Applicative` doesn't cause new type-errors in existing code.
However, moving a method to a top-level binding obviously breaks code that assumes `return` to be a class method. Foremost, code that defines `Monad` instances it at risk:
### Instance Definitions
Code defining `return` as part of an instance definition breaks. However, we had the foresight to provide a default implementation in `base-4.8` for `return` so that the following represents a proper minimal instance definition post-AMP:
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
-- NB: No mention of `return`
Consequently, it is possible to write forward-compatible instances that are valid under this proposal starting with GHC 7.10/`base-4.8`.
Heuristically `grep`ing through Hackage source-code reveals a non-negligible number of packages defining `Monad` instances with explicit `return` definitions[4]. This has a comparable impact to the AMP, and similarly will require a transition scheme aided by compiler warnings.
### Module Import/Export Specifications
A second source of incompatibility may be due to `import`s. Specifically module import that assert `return` to be a method of `Monad`, e.g.:
import Control.Monad (Monad ((>>=), return))
or
import Prelude hiding (Monad(..)) import Control.Monad (Monad(..)) as Monad
f = Monad.return ()
The dual situation can occur when re-exporting `return` via module export specifications.
However, given that `return` is exported by `Prelude` and the examples above are rather artificial, we don't expect this to be a major source of breakage in the case of `return`. In fact, a heuristic grep[5] over Hackage source-code revealed only 21 packages affected.
### Example for writing compatible code
instance Functor Foo where fmap g foo = …
instance Applicative Foo where pure x = … a1 <*> a2 = …
instance Monad Foo where m >>= f = …
#if !(MIN_VERSION_base(4,8,0)) return = pure #endif
Migration Strategy ------------------
The migration strategy is straightforward:
**Phase 1** *(GHC 8.0)*: Implement new warning in GHC which gets triggered when `Monad` instances explicitly override the default `return` method implementation.
**Phase 2** *(GHC 8.2 or later)*: When we're confident that the majority of Hackage has reacted to the warning (with the help of Stackage actively pursuing maintainers to update their packages) we turn the `return` method into a top-level binding and remove the warning implemented in Phase 1 from GHC again.
Discussion period -----------------
A discussion period of three weeks (until 2015-10-15) should be enough to allow everyone to chime in as well as leave enough time to make the required preparations for GHC 8.0 should this proposal pass as we hope.
----
[1]: https://wiki.haskell.org/Functor-Applicative-Monad_Proposal [2]: https://wiki.haskell.org/MonadFail_Proposal [3]: https://ghc.haskell.org/trac/ghc/wiki/ApplicativeDo [4]: https://gist.github.com/hvr/b0e34463d85b58f169d9 [5]: https://gist.github.com/hvr/afcd040783d980594883 [6]: https://ghc.haskell.org/trac/ghc/ticket/9590 [7]: https://mail.haskell.org/pipermail/haskell-prime/2015-September/003936.html
--
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

On Thu, Sep 24, 2015 at 2:43 PM, Herbert Valerio Riedel
TLDR: To complete the AMP, turn `Monad(return)` method into a top-level binding aliasing `Applicative(pure)`.
Sure... if we had a language that no one uses and could keep reforming like putty until it is perfect. But we don't. A modest proposal: We can't keep tinkering with a language and it's libraries like this AND have a growing ecosystem that serves an ever widening base, including the range from newcomer to commercial deployment. SO - Why let's do all the language tinkering in GHC 8 there can be as many prereleases of that as needed until it is just right. ...and leave GHC 7 (7.10? roll back to 7.8.4?) for all of us doing essential and dependable libraries, commercial work, projects on Haskell that we don't want to have to go back and #ifdefs to twice a year just to keep running, educators, people writing books. We can keep improving GHC 7 as needed, and focus on bugs, security issues, patches, cross compatibility, etc. Think of it as Perl 6 or Python 3 for Haskell. - Mark

On Thu, 24 Sep 2015, Herbert Valerio Riedel wrote:
Concluding AMP and MFP, We (David and I) proudly present you the final installment of the Monad trilogy:
Monad of no `return` Proposal =============================
Btw. there were proposals of GHC extensions that allow class hierarchy updates without much code breakage (class aliases) etc. Could we defer the MRP until such extensions are implemented?

On Sun, Oct 18, 2015 at 2:24 PM, Henning Thielemann < lemming@henning-thielemann.de> wrote:
Btw. there were proposals of GHC extensions that allow class hierarchy updates without much code breakage (class aliases) etc. Could we defer the MRP until such extensions are implemented?
There are three things entangled in your request that I'd like to uncouple. 1.) None of those proposals would actually have any impact here: `pure` is already a member of Applicative that people already define. `return` already has a definition in terms of `pure` as its default. 2.) This proposal is definitely being deferred in one sense, nothing can even happen on the warning front until 8.2 at the earliest under the "3 Release Policy" and in practice we'd probably push it back further still given the scope. So you have a couple of years before you'd even hear a peep from the compiler about this saying that hey maybe you might want to consider doing something. 3.) Finally, it isn't clear to me that we're going to be able to achieve a meaningful consensus on how to proceed with superclass defaults. We've been tossing proposals for them around for years. There are at least 3 of them in the wings, with both Richard Eisenberg and Conor McBride having different proposals that yield different end states with varying degrees of prescriptiveness about how they should be used, and some other folks who disbelieve it can be implemented at all in a way that works well with anything more complicated than a linear chain of instances. So while they don't apply to this item, I'm hesitant to incur such a proposal as a blocker on anything when there is no sign of termination in sight and no indication of which way that feature will break in terms of supplied functionality. That is a broader statement as while here they bring nothing to the table that would affect code written under this proposal, elsewhere they could help. -- If we had them at most eventually people would be able to consider (maybe) dropping the manual declaration of Functor, and possibly inline some of their definitions from Applicative into the Monad declaration (depending on which proposal wins favor if any, and if that version of the proposal always complains when it is used like Richard's variant), but the story of pure vs. return doesn't change meaningfully. That said, if a version of the feature showed up over the next 2-3 years in GHC, we'd likely modify the Monoid-Semigroup Proposal to incorporate it as that proposal could benefit, but as above I'd hesitate to tie anything to the fate of a superclass default proposal. Again, none of the changes being proposed have any impacts before 8.2 (or even 8.4 at last check.) -Edward

Hello everybody, Based on the feedback gathered from the discussion, the proposal has been revised to address the raised concerns. The highlights are: - A new stretched out transition scheme complying with the recently enacted 3-release policy (and beyond) has been devised. - Unifying `>>`/`*>` has been incorporated into the proposal in the interest of bundling changes of obviously related changes. - Moreover, the feasibility of automatic refactoring tooling was investigated and resulted in the working `Hs2010To201x` proof-of-concept. Please re-read the revised proposal at https://ghc.haskell.org/trac/ghc/wiki/Proposal/MonadOfNoReturn for more details (or use the Wiki's diffing feature to see what changed relative to the original revision) if you want to comment, so we can focus on discussing the actual revised version. Also, as per proposal guidelines, and more importantly, for the benefit of those that lost track of this rather complex discussion, I've tried to summarize the core of discussion over at https://ghc.haskell.org/wiki/Proposal/MonadOfNoReturn/Discussion More importantly, based on feedback gathered as well as concerns raised throughout the discussion, I've revised and extended the proposal into a "2nd edition MRP". I feel confident the new revised proposal addresses the major concerns as well as adhering to the recently requested 3-yr compatibility policy. PS: One common oversight I noticed when reviewing the discussion is that the last-minute proposal addition -- of unifying `>>`/`*>` in the same vein as `pure`/`return` -- wasn't noticed by many who joined the debate late. However, Unifying `>>`/`*>` and `pure`/`return` are in my opinion strongly related concerns as they share the same rationale about correctness issues and it doesn't make sense to do one without the other. However, the transition time-scales could be set slightly different to account for the more breaking nature of effectively changing `>>`'s current default method operational semantics. Thanks, Herbert

On Thu, Nov 05, 2015 at 11:46:32AM +0100, Herbert Valerio Riedel wrote:
Hello everybody,
Hello, I would suggest to start a new thread for this proposal. The old one (check it on gmane [1]) is approaching "unholy evil" levels of length/nested discussion, a fresh start might benefit the discussion (and result in cleaner archiving). [1] http://thread.gmane.org/gmane.comp.lang.haskell.libraries/25380/focus=118576

Thanks for the clear revisions! It is unclear from the proposal how well
the automatic re-factoring tool is expected to work.
On Thu, Nov 5, 2015 at 6:18 AM, Francesco Ariis
On Thu, Nov 05, 2015 at 11:46:32AM +0100, Herbert Valerio Riedel wrote:
Hello everybody,
Hello, I would suggest to start a new thread for this proposal. The old one (check it on gmane [1]) is approaching "unholy evil" levels of length/nested discussion, a fresh start might benefit the discussion (and result in cleaner archiving).
[1] http://thread.gmane.org/gmane.comp.lang.haskell.libraries/25380/focus=118576 _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 On 05/11/15 15:53, Greg Weber wrote:
Thanks for the clear revisions! It is unclear from the proposal how well the automatic re-factoring tool is expected to work. The obvious answer is that it will be as good as possible. :-]
It would be very beneficial if people who use Haskell in an academic or commercial setting -- thus actively benefiting from it -- were able to spend some of their time on this project. That way the roof for "as good as possible" will likely be raised considerably. - -- Alexander alexander@plaimi.net https://secure.plaimi.net/~alexander -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAEBCgAGBQJWO28fAAoJENQqWdRUGk8Bfm4QAMpMJakhtwopvvJDobr4svZ2 WE4oW88d6LoDIzFTG5654RG78fyKkyGE+WllfH+X1OgV/3/YT1iczE73ysgxS5k4 wivhEzt4HvlITmF8H6qYJDie+X08IHgaCUMseMOhh/fxyy+YF1cr4hF5P9mEWP+9 ti4HC3Y4rjB86U78mbhTVUj6fiF2NLkM7Y2Bxf2vHvbfGwUVh4QA8sSyM7rSSjDP OlZW3fMMNFuhaqvIlYOcr/slHq/r+pe+88X5MJLPen1ALPksjzdyd1Izw1wdCL3y zTGMO94aFlvkbomGCgCUzCFaPUqewvn0P0W5I38jmLM8D7AwRTQBTd/oz53AumsK Km0RtHEs7MW5FQ8dA5+vMLZblxjpXAK9BOvUIkr1Rt44wnDLU86hWEBBFsb5H0+m Kdc5WGfn4AjuESXvG29UrLSyU2eAwYUF60W8Y2hEt9nGs/IrrtSjpC46W5FPi9LR F1GHuYBJobEQ6K6TvjVzQ73ajPH9Vwm3d8+BV8eBd5Z62MkgF23M0HWHuR0JUo4X YjLutYzo+oAkeF4tOzLO0TIvQx6pyncj/CDMZL+ZLMrhHYP2yIuXEQixXs3yi2og GJi453l0RbCEjKj+cPek/ZCwtNtf/tMvSD/Rr6yjCAIE67eaC9h/NsxFn9fNQzRJ O3cfg4wlIvcZDSsx6qGw =jB4v -----END PGP SIGNATURE-----

Hi, On 2015-11-05 at 15:53:39 +0100, Greg Weber wrote:
Thanks for the clear revisions! It is unclear from the proposal how well the automatic re-factoring tool is expected to work.
Currently, Hs2010To201x does the following few things: When a `Monad` instance definition is detected in a module, - if needed, define respective `Functor` instance (AMP) - if needed, define respective `Applicative` instance (AMP) - if needed, refactor return/pure definitions into canonical form (MRP) This works fairly well for most common `Monad` instances. I ran it on Cabal's code-base (for which only the MRP refactoring was relevant), and the result looked very promising: https://gist.github.com/hvr/cd35fbcff9be6f3cb2a9 However, the major obstacle so far is CPP, which generally causes problems with other tooling as well, and in particular /can/ confuse ghc-exactprint. Another source of problems are orphan-instances (specifically when the `Applicative` instance is defined in a different module from the module where the `Monad` instance is defined) as the tool currently operates on single modules at a time. Finally, the less frequent cases of nested Monads which require to construct proper instance constraints for `Functor`/`Applicatives` instances are not handled adequately yet. Examples are `instance (Monad m) => Monad (ListT m)` or `instance (Monad m) => Monad (StateT s m)`. --HVR

Hi Herbert,
On Thu, Nov 5, 2015 at 10:46 AM, Herbert Valerio Riedel
Hello everybody,
Based on the feedback gathered from the discussion, the proposal has been revised to address the raised concerns. The highlights are:
- A new stretched out transition scheme complying with the recently enacted 3-release policy (and beyond) has been devised.
- Unifying `>>`/`*>` has been incorporated into the proposal in the interest of bundling changes of obviously related changes.
- Moreover, the feasibility of automatic refactoring tooling was investigated and resulted in the working `Hs2010To201x` proof-of-concept.
Please re-read the revised proposal at
https://ghc.haskell.org/trac/ghc/wiki/Proposal/MonadOfNoReturn
for more details (or use the Wiki's diffing feature to see what changed relative to the original revision) if you want to comment, so we can focus on discussing the actual revised version.
I'm sorry to join the discussion so late, but I'd like to mention one thing that doesn't seem to have been brought up. If I understand correctly, this proposal can silently slow down existing programs, sometimes even asymptotically. This applies when a monad is defined with no explicit definition for (>>) nor for (*>). The problem is this: currently, when a Monad instance lacks an explicit definition for (>>), a default implementation based on (>>=) is used. After this proposal, (>>) would be an alias for (*>), for which there is a default implementation based on (<*>). However, at least for some monads, the former is a much better default. [1] is one example where it makes an asymptotic difference in runtime. This type of difference arises when (>>=) has to linearly traverse its LHS, but not its RHS. [1] https://ghc.haskell.org/trac/ghc/ticket/10711#comment:1 I also constructed another example [2]. This is a standard implementation of the strict State monad, except that (>>=) is implemented as a NOINLINE function. You can see that using (*>) in place of (>>) changes the memory usage of the program from constant to linear. The difference here arises from the fact that the default implementation for (>>) can "tail-call" its RHS as long as (>>=) also has this tail-call property, but the default implementation of (*>) cannot. [2] https://gist.github.com/takano-akio/7066c511b60d6ab090c5 In my opinion introducing this kind of performance regression is quite bad. Although I agree that it's frustrating that we are stuck with mapM, mapM_ etc., I believe this should be fixed in a way that doesn't make (>>) slower by default. Regards, Takano Akio
Also, as per proposal guidelines, and more importantly, for the benefit of those that lost track of this rather complex discussion, I've tried to summarize the core of discussion over at
https://ghc.haskell.org/wiki/Proposal/MonadOfNoReturn/Discussion
More importantly, based on feedback gathered as well as concerns raised throughout the discussion, I've revised and extended the proposal into a "2nd edition MRP". I feel confident the new revised proposal addresses the major concerns as well as adhering to the recently requested 3-yr compatibility policy.
PS: One common oversight I noticed when reviewing the discussion is that the last-minute proposal addition -- of unifying `>>`/`*>` in the same vein as `pure`/`return` -- wasn't noticed by many who joined the debate late.
However, Unifying `>>`/`*>` and `pure`/`return` are in my opinion strongly related concerns as they share the same rationale about correctness issues and it doesn't make sense to do one without the other. However, the transition time-scales could be set slightly different to account for the more breaking nature of effectively changing `>>`'s current default method operational semantics.
Thanks, Herbert
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

(>>) becomes slower by default in some cases and drastically faster in
others, but since the definition is a member in a class it can actually be
fixed by people.
In situations where (<*>) is asymptotically more efficient than (>>=) then
the default definition in terms of (<*>) wins.
Right now, if you run through hackage there are lots of places where (>>)
has been manually improved but the (*>) has not -- or vice versa. We have
two places where people should apply an optimization and many have only
realized that they should optimize one or the other.
The key here is to encourage folks to actually define (*>) when it matters.
-Edward
On Wed, Nov 25, 2015 at 2:37 AM, Akio Takano
Hi Herbert,
On Thu, Nov 5, 2015 at 10:46 AM, Herbert Valerio Riedel
wrote: Hello everybody,
Based on the feedback gathered from the discussion, the proposal has been revised to address the raised concerns. The highlights are:
- A new stretched out transition scheme complying with the recently enacted 3-release policy (and beyond) has been devised.
- Unifying `>>`/`*>` has been incorporated into the proposal in the interest of bundling changes of obviously related changes.
- Moreover, the feasibility of automatic refactoring tooling was investigated and resulted in the working `Hs2010To201x` proof-of-concept.
Please re-read the revised proposal at
https://ghc.haskell.org/trac/ghc/wiki/Proposal/MonadOfNoReturn
for more details (or use the Wiki's diffing feature to see what changed relative to the original revision) if you want to comment, so we can focus on discussing the actual revised version.
I'm sorry to join the discussion so late, but I'd like to mention one thing that doesn't seem to have been brought up. If I understand correctly, this proposal can silently slow down existing programs, sometimes even asymptotically. This applies when a monad is defined with no explicit definition for (>>) nor for (*>).
The problem is this: currently, when a Monad instance lacks an explicit definition for (>>), a default implementation based on (>>=) is used. After this proposal, (>>) would be an alias for (*>), for which there is a default implementation based on (<*>). However, at least for some monads, the former is a much better default.
[1] is one example where it makes an asymptotic difference in runtime. This type of difference arises when (>>=) has to linearly traverse its LHS, but not its RHS.
[1] https://ghc.haskell.org/trac/ghc/ticket/10711#comment:1
I also constructed another example [2]. This is a standard implementation of the strict State monad, except that (>>=) is implemented as a NOINLINE function. You can see that using (*>) in place of (>>) changes the memory usage of the program from constant to linear. The difference here arises from the fact that the default implementation for (>>) can "tail-call" its RHS as long as (>>=) also has this tail-call property, but the default implementation of (*>) cannot.
[2] https://gist.github.com/takano-akio/7066c511b60d6ab090c5
In my opinion introducing this kind of performance regression is quite bad. Although I agree that it's frustrating that we are stuck with mapM, mapM_ etc., I believe this should be fixed in a way that doesn't make (>>) slower by default.
Regards, Takano Akio
Also, as per proposal guidelines, and more importantly, for the benefit of those that lost track of this rather complex discussion, I've tried to summarize the core of discussion over at
https://ghc.haskell.org/wiki/Proposal/MonadOfNoReturn/Discussion
More importantly, based on feedback gathered as well as concerns raised throughout the discussion, I've revised and extended the proposal into a "2nd edition MRP". I feel confident the new revised proposal addresses the major concerns as well as adhering to the recently requested 3-yr compatibility policy.
PS: One common oversight I noticed when reviewing the discussion is that the last-minute proposal addition -- of unifying `>>`/`*>` in the same vein as `pure`/`return` -- wasn't noticed by many who joined the debate late.
However, Unifying `>>`/`*>` and `pure`/`return` are in my opinion strongly related concerns as they share the same rationale about correctness issues and it doesn't make sense to do one without the other. However, the transition time-scales could be set slightly different to account for the more breaking nature of effectively changing `>>`'s current default method operational semantics.
Thanks, Herbert
_______________________________________________ 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, Nov 25, 2015 at 7:05 PM, Edward Kmett
(>>) becomes slower by default in some cases and drastically faster in others, but since the definition is a member in a class it can actually be fixed by people.
This is true, but I think it's much better to avoid breaking people's code in the first place. Also, since the breakage can be silent, one will not always be able to make a fix promptly.
In situations where (<*>) is asymptotically more efficient than (>>=) then the default definition in terms of (<*>) wins.
You are right. I hadn't thought about this.
Right now, if you run through hackage there are lots of places where (>>) has been manually improved but the (*>) has not -- or vice versa. We have two places where people should apply an optimization and many have only realized that they should optimize one or the other.
The key here is to encourage folks to actually define (*>) when it matters.
I understand this, but perhaps there is a way to achieve this without slowing down existing code. How about introducing a new warning (enabled with -Wall) that is triggered when a type satisfies the following 3 conditions? 1. The type has a Monad instance and an Applicative instance declared in the same module, with the same set of constraints. 2. (*>) is not defined as (*>) = (>>). i.e. either it has a non-trivial definition or its definition is left out. 3. (>>) is not defined as (>>) = (*>). i.e. either it has a non-trivial definition or its definition is left out. This way, people can be warned when (*>) and (>>) can share an implementation but they don't. - Akio
-Edward
On Wed, Nov 25, 2015 at 2:37 AM, Akio Takano
wrote: Hi Herbert,
On Thu, Nov 5, 2015 at 10:46 AM, Herbert Valerio Riedel
wrote: Hello everybody,
Based on the feedback gathered from the discussion, the proposal has been revised to address the raised concerns. The highlights are:
- A new stretched out transition scheme complying with the recently enacted 3-release policy (and beyond) has been devised.
- Unifying `>>`/`*>` has been incorporated into the proposal in the interest of bundling changes of obviously related changes.
- Moreover, the feasibility of automatic refactoring tooling was investigated and resulted in the working `Hs2010To201x` proof-of-concept.
Please re-read the revised proposal at
https://ghc.haskell.org/trac/ghc/wiki/Proposal/MonadOfNoReturn
for more details (or use the Wiki's diffing feature to see what changed relative to the original revision) if you want to comment, so we can focus on discussing the actual revised version.
I'm sorry to join the discussion so late, but I'd like to mention one thing that doesn't seem to have been brought up. If I understand correctly, this proposal can silently slow down existing programs, sometimes even asymptotically. This applies when a monad is defined with no explicit definition for (>>) nor for (*>).
The problem is this: currently, when a Monad instance lacks an explicit definition for (>>), a default implementation based on (>>=) is used. After this proposal, (>>) would be an alias for (*>), for which there is a default implementation based on (<*>). However, at least for some monads, the former is a much better default.
[1] is one example where it makes an asymptotic difference in runtime. This type of difference arises when (>>=) has to linearly traverse its LHS, but not its RHS.
[1] https://ghc.haskell.org/trac/ghc/ticket/10711#comment:1
I also constructed another example [2]. This is a standard implementation of the strict State monad, except that (>>=) is implemented as a NOINLINE function. You can see that using (*>) in place of (>>) changes the memory usage of the program from constant to linear. The difference here arises from the fact that the default implementation for (>>) can "tail-call" its RHS as long as (>>=) also has this tail-call property, but the default implementation of (*>) cannot.
[2] https://gist.github.com/takano-akio/7066c511b60d6ab090c5
In my opinion introducing this kind of performance regression is quite bad. Although I agree that it's frustrating that we are stuck with mapM, mapM_ etc., I believe this should be fixed in a way that doesn't make (>>) slower by default.
Regards, Takano Akio
Also, as per proposal guidelines, and more importantly, for the benefit of those that lost track of this rather complex discussion, I've tried to summarize the core of discussion over at
https://ghc.haskell.org/wiki/Proposal/MonadOfNoReturn/Discussion
More importantly, based on feedback gathered as well as concerns raised throughout the discussion, I've revised and extended the proposal into a "2nd edition MRP". I feel confident the new revised proposal addresses the major concerns as well as adhering to the recently requested 3-yr compatibility policy.
PS: One common oversight I noticed when reviewing the discussion is that the last-minute proposal addition -- of unifying `>>`/`*>` in the same vein as `pure`/`return` -- wasn't noticed by many who joined the debate late.
However, Unifying `>>`/`*>` and `pure`/`return` are in my opinion strongly related concerns as they share the same rationale about correctness issues and it doesn't make sense to do one without the other. However, the transition time-scales could be set slightly different to account for the more breaking nature of effectively changing `>>`'s current default method operational semantics.
Thanks, Herbert
_______________________________________________ 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 2015-11-26 at 09:28:32 +0100, Akio Takano wrote: [...]
I understand this, but perhaps there is a way to achieve this without slowing down existing code. How about introducing a new warning (enabled with -Wall) that is triggered when a type satisfies the following 3 conditions?
1. The type has a Monad instance and an Applicative instance declared in the same module, with the same set of constraints. 2. (*>) is not defined as (*>) = (>>). i.e. either it has a non-trivial definition or its definition is left out. 3. (>>) is not defined as (>>) = (*>). i.e. either it has a non-trivial definition or its definition is left out.
This way, people can be warned when (*>) and (>>) can share an implementation but they don't.
Coincidentally, I've recently implemented something similar to that end (but it is *not* enabled via -Wall/-Wcompat by default yet), see https://git.haskell.org/ghc.git/commitdiff/f09f2470a76bb08b7f51d2f5663daa672... for details. Cheers, hvr

On Thu, Nov 26, 2015 at 8:36 AM, Herbert Valerio Riedel
On 2015-11-26 at 09:28:32 +0100, Akio Takano wrote:
[...]
I understand this, but perhaps there is a way to achieve this without slowing down existing code. How about introducing a new warning (enabled with -Wall) that is triggered when a type satisfies the following 3 conditions?
1. The type has a Monad instance and an Applicative instance declared in the same module, with the same set of constraints. 2. (*>) is not defined as (*>) = (>>). i.e. either it has a non-trivial definition or its definition is left out. 3. (>>) is not defined as (>>) = (*>). i.e. either it has a non-trivial definition or its definition is left out.
This way, people can be warned when (*>) and (>>) can share an implementation but they don't.
Coincidentally, I've recently implemented something similar to that end (but it is *not* enabled via -Wall/-Wcompat by default yet), see
https://git.haskell.org/ghc.git/commitdiff/f09f2470a76bb08b7f51d2f5663daa672...
for details.
Thank you for the information. If I understand correctly, this -fwarn-noncanonical-monad-instances warning doesn't address my concern, because it won't warn about a monad that defines neither (>>) nor (*>) explicitly, which I expect to be a common case. - Akio
Cheers, hvr

Hi, On 2015-11-27 at 10:29:09 +0100, Akio Takano wrote: [...]
Thank you for the information. If I understand correctly, this -fwarn-noncanonical-monad-instances warning doesn't address my concern, because it won't warn about a monad that defines neither (>>) nor (*>) explicitly, which I expect to be a common case.
You're right, from what I've seen the majority of Monad instances don't bother to override (>>)/(*>) currently. But do we really want every Applicative/Monad to explicitly define (*>) (and consequently (>>)=(*>)) ? If so, it seems to be unfortunate that we have an overridable default implementation for (*>)/(>>) in place, as that IMO suggests that you're only supposed to override (*>) in those less common cases where it provides a benefit over the default implementation. What's the point of the default implementation otherwise? -- hvr

On Fri, Nov 27, 2015 at 9:42 AM, Herbert Valerio Riedel
You're right, from what I've seen the majority of Monad instances don't bother to override (>>)/(*>) currently.
But do we really want every Applicative/Monad to explicitly define (*>) (and consequently (>>)=(*>)) ?
You are right, this indeed seems like a strange thing to require. However I believe that this is much better than silently changing the default definition for (>>) to something that potentially has worse asymptotic behaviors. Of course another option is to keep (>>) in the Monad class. - Akio
If so, it seems to be unfortunate that we have an overridable default implementation for (*>)/(>>) in place, as that IMO suggests that you're only supposed to override (*>) in those less common cases where it provides a benefit over the default implementation. What's the point of the default implementation otherwise?
-- hvr

On Thu, Nov 26, 2015 at 3:28 AM, Akio Takano
This is true, but I think it's much better to avoid breaking people's code in the first place. Also, since the breakage can be silent, one will not always be able to make a fix promptly.
We're not talking about making this change until we can get some warnings in place. That said, in the presence of some existing combinators that have already been generalized from Monad to Applicative you may want to ensure that these definitions have been fixed already.
In situations where (<*>) is asymptotically more efficient than (>>=) then the default definition in terms of (<*>) wins.
You are right. I hadn't thought about this.
Right now, if you run through hackage there are lots of places where (>>) has been manually improved but the (*>) has not -- or vice versa. We have two places where people should apply an optimization and many have only realized that they should optimize one or the other.
The key here is to encourage folks to actually define (*>) when it
matters.
I understand this, but perhaps there is a way to achieve this without slowing down existing code. How about introducing a new warning (enabled with -Wall) that is triggered when a type satisfies the following 3 conditions?
1. The type has a Monad instance and an Applicative instance declared in the same module, with the same set of constraints. 2. (*>) is not defined as (*>) = (>>). i.e. either it has a non-trivial definition or its definition is left out. 3. (>>) is not defined as (>>) = (*>). i.e. either it has a non-trivial definition or its definition is left out.
This way, people can be warned when (*>) and (>>) can share an implementation but they don't.
This is pretty much what Herbert has been working on, except with the definition biased in favor of (>>) = (*>) being expected, and the other becoming a warning as that definition blows up when and if we later move (>>) out of the class. -Edward

On Thu, Nov 26, 2015 at 5:08 PM, Edward Kmett
On Thu, Nov 26, 2015 at 3:28 AM, Akio Takano
wrote: This is true, but I think it's much better to avoid breaking people's code in the first place. Also, since the breakage can be silent, one will not always be able to make a fix promptly.
We're not talking about making this change until we can get some warnings in place.
I would appreciate such a warning. I was concerned because I didn't find a plan for one on the proposal page. In particular, neither the proposed -fwarn-mrp-compat flag nor the implemented -fwarn-noncanonical-monad-instances flag seemed to protect a programmer from the issue of silent performance regression, when there is no explicit definition for (*>) nor for (>>).
That said, in the presence of some existing combinators that have already been generalized from Monad to Applicative you may want to ensure that these definitions have been fixed already.
In situations where (<*>) is asymptotically more efficient than (>>=) then the default definition in terms of (<*>) wins.
You are right. I hadn't thought about this.
Right now, if you run through hackage there are lots of places where (>>) has been manually improved but the (*>) has not -- or vice versa. We have two places where people should apply an optimization and many have only realized that they should optimize one or the other.
The key here is to encourage folks to actually define (*>) when it matters.
I understand this, but perhaps there is a way to achieve this without slowing down existing code. How about introducing a new warning (enabled with -Wall) that is triggered when a type satisfies the following 3 conditions?
1. The type has a Monad instance and an Applicative instance declared in the same module, with the same set of constraints. 2. (*>) is not defined as (*>) = (>>). i.e. either it has a non-trivial definition or its definition is left out. 3. (>>) is not defined as (>>) = (*>). i.e. either it has a non-trivial definition or its definition is left out.
This way, people can be warned when (*>) and (>>) can share an implementation but they don't.
This is pretty much what Herbert has been working on, except with the definition biased in favor of (>>) = (*>) being expected, and the other becoming a warning as that definition blows up when and if we later move (>>) out of the class.
Probably I wasn't clear, but I actually wanted to suggest a warning as a replacement for (the (>>)-related half of) MRP, not as a migration path to it. If the goal is to encourage people to have a good implementation for (*>), it may be achievable with just a warning, with no change to the class hierarchy. That said, I can imagine having a warning like this as a migration path. In that case we could provide a function like thenDefaultByBind :: (Monad m) => m a -> m b -> m b thenDefaultByBind a b = a >>= \_ -> b and give people an option to define (*>) = thenDefaultByBind in their Applicative instances. - Akio
-Edward

I understand that you'd prefer it as a replacement for this plan than as a
supplement, but I don't think that that would work all that well. We
already have half a dozen combinators in Control.Monad generalized, more
are generalizing in 7.10. e.g. We don't want to introduce a 'replicateA_'
for instance as the pattern has been to generalize the existing 'M'
combinators where possible.
What you propose would leave us paralyzed in an difficult to explain middle
ground indefinitely.
As for making a thenM or thenDefault or thenDefaultByBind to make it easier
to define (*>), I'm 100% on board with that.
-Edward
On Fri, Nov 27, 2015 at 4:50 AM, Akio Takano
On Thu, Nov 26, 2015 at 5:08 PM, Edward Kmett
wrote: On Thu, Nov 26, 2015 at 3:28 AM, Akio Takano
wrote: This is true, but I think it's much better to avoid breaking people's code in the first place. Also, since the breakage can be silent, one will not always be able to make a fix promptly.
We're not talking about making this change until we can get some warnings in place.
I would appreciate such a warning. I was concerned because I didn't find a plan for one on the proposal page. In particular, neither the proposed -fwarn-mrp-compat flag nor the implemented -fwarn-noncanonical-monad-instances flag seemed to protect a programmer from the issue of silent performance regression, when there is no explicit definition for (*>) nor for (>>).
That said, in the presence of some existing combinators that have already been generalized from Monad to Applicative you may want to ensure that
these
definitions have been fixed already.
In situations where (<*>) is asymptotically more efficient than (>>=) then the default definition in terms of (<*>) wins.
You are right. I hadn't thought about this.
Right now, if you run through hackage there are lots of places where (>>) has been manually improved but the (*>) has not -- or vice versa. We have two places where people should apply an optimization and many have
only
realized that they should optimize one or the other.
The key here is to encourage folks to actually define (*>) when it matters.
I understand this, but perhaps there is a way to achieve this without slowing down existing code. How about introducing a new warning (enabled with -Wall) that is triggered when a type satisfies the following 3 conditions?
1. The type has a Monad instance and an Applicative instance declared in the same module, with the same set of constraints. 2. (*>) is not defined as (*>) = (>>). i.e. either it has a non-trivial definition or its definition is left out. 3. (>>) is not defined as (>>) = (*>). i.e. either it has a non-trivial definition or its definition is left out.
This way, people can be warned when (*>) and (>>) can share an implementation but they don't.
This is pretty much what Herbert has been working on, except with the definition biased in favor of (>>) = (*>) being expected, and the other becoming a warning as that definition blows up when and if we later move (>>) out of the class.
Probably I wasn't clear, but I actually wanted to suggest a warning as a replacement for (the (>>)-related half of) MRP, not as a migration path to it. If the goal is to encourage people to have a good implementation for (*>), it may be achievable with just a warning, with no change to the class hierarchy.
That said, I can imagine having a warning like this as a migration path. In that case we could provide a function like
thenDefaultByBind :: (Monad m) => m a -> m b -> m b thenDefaultByBind a b = a >>= \_ -> b
and give people an option to define
(*>) = thenDefaultByBind
in their Applicative instances.
- Akio
-Edward
participants (41)
-
Akio Takano
-
Alexander Berntsen
-
amindfv@gmail.com
-
Andreas Abel
-
Bardur Arantsson
-
Bart Massey
-
Ben Gamari
-
Bertram Felgenhauer
-
Carter Schonwald
-
Christopher Allen
-
Dan Burton
-
David Feuer
-
David Luposchainsky
-
Edward Kmett
-
Evan Laforge
-
Francesco Ariis
-
Greg Weber
-
Henning Thielemann
-
Henrik Nilsson
-
Herbert Valerio Riedel
-
Herbert Valerio Riedel
-
Imants Cekusins
-
John Lato
-
John Wiegley
-
Julian Bean
-
M Farkas-Dyck
-
Malcolm Wallace
-
Manuel Gómez
-
Marcin Mrotek
-
Mario Blažević
-
Mario Blažević
-
Mark Lentczner
-
Michael Walker
-
Reid Barton
-
Richard Eisenberg
-
Roman Cheplyaka
-
S. Doaitse Swierstra
-
Taru Karttunen
-
Vincent Hanquez
-
wren romano
-
Yitzchak Gale