Commit 96a37685 authored by Ross Paterson's avatar Ross Paterson
Browse files

tweak documentation of mdo/rec

parent 6697dbb2
......@@ -866,7 +866,12 @@ To disable it, you can use the <option>-XNoTraditionalRecordSyntax</option> flag
<para>
It turns out that such recursive bindings do indeed make sense for a variety of monads, but
not all. In particular, recursion in this sense requires a fixed-point operator for the underlying
monad, captured by the <literal>mfix</literal> method of the <literal>MonadFix</literal> class. Haskell's
monad, captured by the <literal>mfix</literal> method of the <literal>MonadFix</literal> class, defined in <literal>Control.Monad.Fix</literal> as follows:
<programlisting>
class Monad m => MonadFix m where
mfix :: (a -> m a) -> m a
</programlisting>
Haskell's
<literal>Maybe</literal>, <literal>[]</literal> (list), <literal>ST</literal> (both strict and lazy versions),
<literal>IO</literal>, and many other monads have <literal>MonadFix</literal> instances. On the negative
side, the continuation monad, with the signature <literal>(a -> r) -> r</literal>, does not.
......@@ -876,8 +881,9 @@ To disable it, you can use the <option>-XNoTraditionalRecordSyntax</option> flag
For monads that do belong to the <literal>MonadFix</literal> class, GHC provides
an extended version of the do-notation that allows recursive bindings.
The <option>-XRecursiveDo</option> (language pragma: <literal>RecursiveDo</literal>)
provides the necessary syntactic support, introducing the keyword <literal>mdo</literal>. Unlike
bindings in a <literal>do</literal> expression, those introduced by <literal>mdo</literal>
provides the necessary syntactic support, introducing the keywords <literal>mdo</literal> and
<literal>rec</literal> for higher and lower levels of the notation respectively. Unlike
bindings in a <literal>do</literal> expression, those introduced by <literal>mdo</literal> and <literal>rec</literal>
are recursively defined, much like in an ordinary let-expression. Due to the new
keyword <literal>mdo</literal>, we also call this notation the <emphasis>mdo-notation</emphasis>.
</para>
......@@ -889,6 +895,12 @@ To disable it, you can use the <option>-XNoTraditionalRecordSyntax</option> flag
justOnes = mdo { xs &lt;- Just (1:xs)
; return (map negate xs) }
</programlisting>
or equivalently
<programlisting>
{-# LANGUAGE RecursiveDo #-}
justOnes = do { rec { xs &lt;- Just (1:xs) }
; return (map negate xs) }
</programlisting>
As you can guess <literal>justOnes</literal> will evaluate to <literal>Just [-1,-1,-1,...</literal>.
</para>
......@@ -896,8 +908,8 @@ As you can guess <literal>justOnes</literal> will evaluate to <literal>Just [-1,
GHC's implementation the mdo-notation closely follows the original translation as described in the paper
<ulink url="https://sites.google.com/site/leventerkok/recdo.pdf">A recursive do for Haskell</ulink>, which
in turn is based on the work <ulink url="http://sites.google.com/site/leventerkok/erkok-thesis.pdf">Value Recursion
in Monadic Computations</ulink>. Furthermore, GHC extends the syntax described in the former paper by the
additional <literal>rec</literal> keyword, as we describe next.
in Monadic Computations</ulink>. Furthermore, GHC extends the syntax described in the former paper
with a lower level syntax flagged by the <literal>rec</literal> keyword, as we describe next.
</para>
<sect3>
......@@ -939,9 +951,9 @@ rec { b &lt;- f a c ===> (b,c) &lt;- mfix (\~(b,c) -> do { b &lt;- f a c
</para>
<para>
Note in particular that the translation for a <literal>rec</literal> block only involves wrapping around a call
to <literal>mfix</literal>: otherwise it does not perform any other analysis on the bindings at all. The latter is the task
for the <literal>mdo</literal> notation, as we describe next.
Note in particular that the translation for a <literal>rec</literal> block only involves wrapping a call
to <literal>mfix</literal>: it performs no other analysis on the bindings. The latter is the task
for the <literal>mdo</literal> notation, which is described next.
</para>
</sect3>
......@@ -950,11 +962,11 @@ rec { b &lt;- f a c ===> (b,c) &lt;- mfix (\~(b,c) -> do { b &lt;- f a c
<para>
A <literal>rec</literal>-block tells the compiler where precisely the recursive knot should be tied. It turns out that
the placement of the recursive knots can be rather delicate: In particular, we would like the knots to be wrapped
around as minimal groups as possible. This process is known as <emphasis>segmentation</emphasis>, an is described
the placement of the recursive knots can be rather delicate: in particular, we would like the knots to be wrapped
around as minimal groups as possible. This process is known as <emphasis>segmentation</emphasis>, and is described
in detail in Secton 3.2 of <ulink url="https://sites.google.com/site/leventerkok/recdo.pdf">A recursive do for
Haskell</ulink>. Segmentation improves polymorphism and reduces the size of the recursive knot. Most importantly, it avoids
unnecessary interference caused by a fundamental issue with the so called <emphasis>right-shrinking</emphasis>
unnecessary interference caused by a fundamental issue with the so-called <emphasis>right-shrinking</emphasis>
axiom for monadic recursion. In brief, most monads of interest (IO, strict state, etc.) do <emphasis>not</emphasis>
have recursion operators that satisfy this axiom, and thus not performing segmentation can cause unnecessary
interference, changing the termination behavior of the resulting translation.
......@@ -974,7 +986,7 @@ rec { b &lt;- f a c ===> (b,c) &lt;- mfix (\~(b,c) -> do { b &lt;- f a c
</para>
<para>
Here's an example <literal>mdo</literal>-expression, and its translation to <literal>rec</literal> blocks:
Here is an example <literal>mdo</literal>-expression, and its translation to <literal>rec</literal> blocks:
<programlisting>
mdo { a &lt;- getChar ===> do { a &lt;- getChar
; b &lt;- f a c ; rec { b &lt;- f a c
......@@ -995,12 +1007,7 @@ would expect.
<literal>rec</literal> blocks to wrap over minimal recursive groups. Then, each resulting
<literal>rec</literal> is desugared, using a call to <literal>Control.Monad.Fix.mfix</literal> as described
in the previous section. The original <literal>mdo</literal>-expression typechecks exactly when the desugared
version would do so. The <literal>mfix</literal> function is defined in the <literal>MonadFix</literal>
class, in <literal>Control.Monad.Fix</literal>, thusly:
<programlisting>
class Monad m => MonadFix m where
mfix :: (a -> m a) -> m a
</programlisting>
version would do so.
</para>
<para>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment