8 | | An extended form of `do` notation allowing feedback for monads in the [http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Monad-Fix.html MonadFix] class. |
9 | | |
10 | | Recursive do is invoked via the 'mdo' keyword rather than the normal 'do' one, a MonadFix constraint is added to the Monad when 'mdo' is used. Some advocate replacing 'do' with 'mdo' always. |
11 | | |
12 | | There are connections to the proposed syntactic support for [wiki:Arrows Arrows] using an extended form of `do`-noation. In particular, the |
13 | | [wiki:Arrows Arrows]extension has its own syntax for recursive bindings/feedback. It would clearly be preferable if there was only one variant of |
14 | | recursive `do`. Even if the Arrows extensions are not adopted, it does offer a different explicit syntax for recursive bindings through the keyword |
15 | | `rec` that arguably is a bit more suggestive of its meaning than `mdo`. Conversely, if it is decided to go for implicit recursion, then it would |
16 | | seem reasonable to opt for the same in the case of Arrows, if possible. If not, then that might be another argument against implicit |
17 | | recursion. |
| 8 | An extended form of `do` notation allowing value recursion (or feedback) for monads in the [http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Monad-Fix.html MonadFix] class. |
| 15 | == Variations == |
| 16 | |
| 17 | Using `mfix` adds a `MonadFix` constraint, and also affects the semantics for some monads, so a key choice is how `mfix` is introduced. |
| 18 | As an experiment, two syntaxes are implemented in GHC, both for `do`-notation and [wiki:Arrows arrow notation]. |
| 19 | It would clearly be preferable if there was only one variant of recursive `do`, even if arrow notation is not adopted. |
| 20 | |
| 21 | === Implicit recursion === |
| 22 | |
| 23 | (as implemented in GHC and Hugs) |
| 24 | |
| 25 | A dependency analysis is performed over the list of statements, and minimal subsequences of interdependent statements are translated using `mfix`. |
| 26 | That is, a variable used before it is bound is treated as recursively defined, while in a Haskell 98 `do`-statement it would be treated as shadowed. |
| 27 | |
| 28 | To retain backwards compatibility, existing implementations use a different keyword (`mdo`) for expressions treated in this way, and always add a `MonadFix` constraint to these expressions. |
| 29 | An alternative is to extend the ordinary `do`-notation, sacrificing backwards compatibility. |
| 30 | In that case, the `MonadFix` constraint would be added only if a recursive binding was present. |
| 31 | |
| 32 | '''Cons''' |
| 33 | * either use another keyword for a second kind of `do`-statement, or break backwards compatibility. Opinion is divided on the value of variable shadowing. |
| 34 | * a dependency analysis is required to determine the semantics, making it significantly more difficult to understand the desugaring. |
| 35 | |
| 36 | (The same approaches also work for arrow notation, with the same trade-offs.) |
| 37 | |
| 38 | === Explicit recursion === |
| 39 | |
| 40 | (as implemented in the `do` part of [wiki:Arrows arrow notation] and also in plain `do` in GHC with `-farrows`) |
| 41 | |
| 42 | Add to the current `do`-notation a new `rec` statement containing a sequence of mutually recursive statements. |
| 43 | The `rec` keyword is a bit more suggestive of its meaning than `mdo`. |
| 44 | The extent of the recursion is explicit, though implementations can trim non-recursive variables from the feedback set without changing the semantics. |
| 45 | |
| 46 | '''Cons''' |
| 47 | * contrasts with `let`/`where` bindings, in which recursion is implicit. |
| 48 | * `rec` is a common identifier. |