The proposal monad of no return has been in the process of being implemented for a while. I’m collecting community feedback on the proposal (and specifically phase 3) in the hopes that as a community we can move forwards in making Haskell a better language. I encourage people to read the proposal above, but I’ll summarise and quote below where relevant.
What is this proposal?
The proposal outlines that with making Applicative a superclass of Monad (which happened with Functor-Applicative-Monad proposal pre-2015), the definitions of return and (>>) in the Monad typeclass are redundant, as they can always be lawfully expressed in terms of pure and (*>) respectively. As such, they can and (by this proposal) should be removed from the typeclass, and defined in terms of their Applicative equivalents.
Why should we do this?
Having return and (>>) introduces redundancy, redundancy that
violates the “making illegal states unrepresentable” idiom: Due to the default implementation of return this redundancy leads to error-prone situations which aren’t caught by the compiler; for instance, when
returnis removed while theApplicativeinstance is left with apure = returndefinition, this leads to a cyclic definition which can be quite tedious to debug as it only manifests at runtime by a hanging process. [1]
Additionally, keeping return and (>>) as Monad methods means that in cases where a weaker Applicative constraint would suffice we instead get a Monad constraint.
Currently the status quo is to optimise (>>) over (*>), which means that there are unexpected performance regressions[1] when generalising code; this is particularly noteworthy in the case of Foldable/Traversable methods, and additionally blocks the collation of their methods (for example mapM vs traverse) too.
A minor benefit would be to reduce the sizes of the class dictionaries, as well as avoid additional indirection through Monad when Applicative will suffice.
What’s been done so far?
So far we’ve completed phase 1 of the migration strategy. Phase 1 introduced a warning when non-lawful instances of return and (>>) are defined. This was implemented in GHC 8.0, and added to the default warning set in GHC 9.2.
What’s next?
Phase 2 moves return and (>>) to be top level definitions, and lets GHC ignore lawful definitions of return and (>>) in Monad. As part of this, non-lawful definitions would result in a compile time error, while lawful definitions are left alone.
Phase 3 would then start warning about lawful implementations, similar to phase 1’s warning on unlawful implementations.
Phase 4 would finish off the proposal by removing GHC support for return and (>>) overrides, turning any such override into a compile time error.
So why are you posting about this?
It’s been a while since there’s been much update on this front, which is a shame for a proposal that would make Haskell a cleaner and more coherent language to program in. For many, the move to phase 2 won’t impact them, as unlawful definitions have been warned against for a time. Phase 3 has the potential to impact more people, so that is the primary focus of this post.
Why is phase 3 a sticking point?
It isn’t! What is currently lacking is community input in order to make the changes that phase 3, and this proposal, represents digestible and easily understood by the majority of Haskell users. We’re in no rush to break setups or have confused beginners ask why their tutorials are failing them.
What are we meant to do about this?
Getting feedback from the community is the primary purpose of this post, but I’m also taking the opportunity to ask for volunteers to split the work and make progress on this issue. If you want to take part, please let people know! GHC is a community project after all.