Commit | Line | Data |
---|---|---|
7f918cf1 CE |
1 | <!DOCTYPE html>\r |
2 | <html lang="en">\r | |
3 | <head>\r | |
4 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">\r | |
5 | <meta name="generator" content="AsciiDoc 8.6.9">\r | |
6 | <title>StaticSum</title>\r | |
7 | <link rel="stylesheet" href="./asciidoc.css" type="text/css">\r | |
8 | <link rel="stylesheet" href="./pygments.css" type="text/css">\r | |
9 | \r | |
10 | \r | |
11 | <script type="text/javascript" src="./asciidoc.js"></script>\r | |
12 | <script type="text/javascript">\r | |
13 | /*<![CDATA[*/\r | |
14 | asciidoc.install();\r | |
15 | /*]]>*/\r | |
16 | </script>\r | |
17 | <link rel="stylesheet" href="./mlton.css" type="text/css">\r | |
18 | </head>\r | |
19 | <body class="article">\r | |
20 | <div id="banner">\r | |
21 | <div id="banner-home">\r | |
22 | <a href="./Home">MLton 20180207</a>\r | |
23 | </div>\r | |
24 | </div>\r | |
25 | <div id="header">\r | |
26 | <h1>StaticSum</h1>\r | |
27 | </div>\r | |
28 | <div id="content">\r | |
29 | <div id="preamble">\r | |
30 | <div class="sectionbody">\r | |
31 | <div class="paragraph"><p>While SML makes it impossible to write functions whose types would\r | |
32 | depend on the values of their arguments, or so called dependently\r | |
33 | typed functions, it is possible, and arguably commonplace, to write\r | |
34 | functions whose types depend on the types of their arguments. Indeed,\r | |
35 | the types of parametrically polymorphic functions like <span class="monospaced">map</span> and\r | |
36 | <span class="monospaced">foldl</span> can be said to depend on the types of their arguments. What\r | |
37 | is less commonplace, however, is to write functions whose behavior\r | |
38 | would depend on the types of their arguments. Nevertheless, there are\r | |
39 | several techniques for writing such functions.\r | |
40 | <a href="TypeIndexedValues">Type-indexed values</a> and <a href="Fold">fold</a> are two such\r | |
41 | techniques. This page presents another such technique dubbed static\r | |
42 | sums.</p></div>\r | |
43 | </div>\r | |
44 | </div>\r | |
45 | <div class="sect1">\r | |
46 | <h2 id="_ordinary_sums">Ordinary Sums</h2>\r | |
47 | <div class="sectionbody">\r | |
48 | <div class="paragraph"><p>Consider the sum type as defined below:</p></div>\r | |
49 | <div class="listingblock">\r | |
50 | <div class="content"><div class="highlight"><pre><span class="k">structure</span><span class="w"> </span><span class="n">Sum</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">struct</span><span class="w"></span>\r | |
51 | <span class="w"> </span><span class="k">datatype</span><span class="w"> </span><span class="p">(</span><span class="n">'a</span><span class="p">,</span><span class="w"> </span><span class="n">'b</span><span class="p">)</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">INL</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">'a</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="n">INR</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">'b</span><span class="w"></span>\r | |
52 | <span class="k">end</span><span class="w"></span>\r | |
53 | </pre></div></div></div>\r | |
54 | <div class="paragraph"><p>While a generic sum type such as defined above is very useful, it has\r | |
55 | a number of limitations. As an example, we could write the function\r | |
56 | <span class="monospaced">out</span> to extract the value from a sum as follows:</p></div>\r | |
57 | <div class="listingblock">\r | |
58 | <div class="content"><div class="highlight"><pre><span class="k">fun</span><span class="w"> </span><span class="n">out</span><span class="w"> </span><span class="p">(</span><span class="n">s</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">'a</span><span class="p">,</span><span class="w"> </span><span class="n">'a</span><span class="p">)</span><span class="w"> </span><span class="n">Sum</span><span class="p">.</span><span class="n">t</span><span class="p">)</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">'a</span><span class="w"> </span><span class="p">=</span><span class="w"></span>\r | |
59 | <span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="n">s</span><span class="w"></span>\r | |
60 | <span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">Sum</span><span class="p">.</span><span class="n">INL</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">a</span><span class="w"></span>\r | |
61 | <span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="n">Sum</span><span class="p">.</span><span class="n">INR</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">a</span><span class="w"></span>\r | |
62 | </pre></div></div></div>\r | |
63 | <div class="paragraph"><p>As can be seen from the type of <span class="monospaced">out</span>, it is limited in the sense that\r | |
64 | it requires both variants of the sum to have the same type. So, <span class="monospaced">out</span>\r | |
65 | cannot be used to extract the value of a sum of two different types,\r | |
66 | such as the type <span class="monospaced">(int, real) Sum.t</span>. As another example of a\r | |
67 | limitation, consider the following attempt at a <span class="monospaced">succ</span> function:</p></div>\r | |
68 | <div class="listingblock">\r | |
69 | <div class="content"><div class="highlight"><pre><span class="k">fun</span><span class="w"> </span><span class="n">succ</span><span class="w"> </span><span class="p">(</span><span class="n">s</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">int</span><span class="p">,</span><span class="w"> </span><span class="n">real</span><span class="p">)</span><span class="w"> </span><span class="n">Sum</span><span class="p">.</span><span class="n">t</span><span class="p">)</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">???</span><span class="w"> </span><span class="p">=</span><span class="w"></span>\r | |
70 | <span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="n">s</span><span class="w"></span>\r | |
71 | <span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">Sum</span><span class="p">.</span><span class="n">INL</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="n">+</span><span class="w"> </span><span class="mi">1</span><span class="w"></span>\r | |
72 | <span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="n">Sum</span><span class="p">.</span><span class="n">INR</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">Real</span><span class="p">.</span><span class="n">nextAfter</span><span class="w"> </span><span class="p">(</span><span class="n">r</span><span class="p">,</span><span class="w"> </span><span class="n">Real</span><span class="p">.</span><span class="n">posInf</span><span class="p">)</span><span class="w"></span>\r | |
73 | </pre></div></div></div>\r | |
74 | <div class="paragraph"><p>The above definition of <span class="monospaced">succ</span> cannot be typed, because there is no\r | |
75 | type for the codomain within SML.</p></div>\r | |
76 | </div>\r | |
77 | </div>\r | |
78 | <div class="sect1">\r | |
79 | <h2 id="_static_sums">Static Sums</h2>\r | |
80 | <div class="sectionbody">\r | |
81 | <div class="paragraph"><p>Interestingly, it is possible to define values <span class="monospaced">inL</span>, <span class="monospaced">inR</span>, and\r | |
82 | <span class="monospaced">match</span> that satisfy the laws</p></div>\r | |
83 | <div class="listingblock">\r | |
84 | <div class="content monospaced">\r | |
85 | <pre>match (inL x) (f, g) = f x\r | |
86 | match (inR x) (f, g) = g x</pre>\r | |
87 | </div></div>\r | |
88 | <div class="paragraph"><p>and do not suffer from the same limitions. The definitions are\r | |
89 | actually quite trivial:</p></div>\r | |
90 | <div class="listingblock">\r | |
91 | <div class="content"><div class="highlight"><pre><span class="k">structure</span><span class="w"> </span><span class="n">StaticSum</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">struct</span><span class="w"></span>\r | |
92 | <span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">inL</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">(</span><span class="n">f</span><span class="p">,</span><span class="w"> </span><span class="p">_)</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="n">x</span><span class="w"></span>\r | |
93 | <span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">inR</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">(_,</span><span class="w"> </span><span class="n">g</span><span class="p">)</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">g</span><span class="w"> </span><span class="n">x</span><span class="w"></span>\r | |
94 | <span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">match</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">x</span><span class="w"></span>\r | |
95 | <span class="k">end</span><span class="w"></span>\r | |
96 | </pre></div></div></div>\r | |
97 | <div class="paragraph"><p>Now, given the <span class="monospaced">succ</span> function defined as</p></div>\r | |
98 | <div class="listingblock">\r | |
99 | <div class="content"><div class="highlight"><pre><span class="k">fun</span><span class="w"> </span><span class="n">succ</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="p">=</span><span class="w"></span>\r | |
100 | <span class="w"> </span><span class="n">StaticSum</span><span class="p">.</span><span class="n">match</span><span class="w"> </span><span class="n">s</span><span class="w"></span>\r | |
101 | <span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="n">+</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"></span>\r | |
102 | <span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">Real</span><span class="p">.</span><span class="n">nextAfter</span><span class="w"> </span><span class="p">(</span><span class="n">r</span><span class="p">,</span><span class="w"> </span><span class="n">Real</span><span class="p">.</span><span class="n">posInf</span><span class="p">))</span><span class="w"></span>\r | |
103 | </pre></div></div></div>\r | |
104 | <div class="paragraph"><p>we get</p></div>\r | |
105 | <div class="listingblock">\r | |
106 | <div class="content"><div class="highlight"><pre><span class="n">succ</span><span class="w"> </span><span class="p">(</span><span class="n">StaticSum</span><span class="p">.</span><span class="n">inL</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>\r | |
107 | <span class="n">succ</span><span class="w"> </span><span class="p">(</span><span class="n">StaticSum</span><span class="p">.</span><span class="n">inR</span><span class="w"> </span><span class="n">Real</span><span class="p">.</span><span class="n">maxFinite</span><span class="p">)</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Real</span><span class="p">.</span><span class="n">posInf</span><span class="w"></span>\r | |
108 | </pre></div></div></div>\r | |
109 | <div class="paragraph"><p>To better understand how this works, consider the following signature\r | |
110 | for static sums:</p></div>\r | |
111 | <div class="listingblock">\r | |
112 | <div class="content"><div class="highlight"><pre><span class="k">structure</span><span class="w"> </span><span class="n">StaticSum</span><span class="w"> </span><span class="p">:></span><span class="w"> </span><span class="k">sig</span><span class="w"></span>\r | |
113 | <span class="w"> </span><span class="k">type</span><span class="w"> </span><span class="p">(</span><span class="n">'dL</span><span class="p">,</span><span class="w"> </span><span class="n">'cL</span><span class="p">,</span><span class="w"> </span><span class="n">'dR</span><span class="p">,</span><span class="w"> </span><span class="n">'cR</span><span class="p">,</span><span class="w"> </span><span class="n">'c</span><span class="p">)</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r | |
114 | <span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">inL</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">'dL</span><span class="w"> </span><span class="p">-></span><span class="w"> </span><span class="p">(</span><span class="n">'dL</span><span class="p">,</span><span class="w"> </span><span class="n">'cL</span><span class="p">,</span><span class="w"> </span><span class="n">'dR</span><span class="p">,</span><span class="w"> </span><span class="n">'cR</span><span class="p">,</span><span class="w"> </span><span class="n">'cL</span><span class="p">)</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r | |
115 | <span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">inR</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">'dR</span><span class="w"> </span><span class="p">-></span><span class="w"> </span><span class="p">(</span><span class="n">'dL</span><span class="p">,</span><span class="w"> </span><span class="n">'cL</span><span class="p">,</span><span class="w"> </span><span class="n">'dR</span><span class="p">,</span><span class="w"> </span><span class="n">'cR</span><span class="p">,</span><span class="w"> </span><span class="n">'cR</span><span class="p">)</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r | |
116 | <span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">match</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">'dL</span><span class="p">,</span><span class="w"> </span><span class="n">'cL</span><span class="p">,</span><span class="w"> </span><span class="n">'dR</span><span class="p">,</span><span class="w"> </span><span class="n">'cR</span><span class="p">,</span><span class="w"> </span><span class="n">'c</span><span class="p">)</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="p">-></span><span class="w"> </span><span class="p">(</span><span class="n">'dL</span><span class="w"> </span><span class="p">-></span><span class="w"> </span><span class="n">'cL</span><span class="p">)</span><span class="w"> </span><span class="n">*</span><span class="w"> </span><span class="p">(</span><span class="n">'dR</span><span class="w"> </span><span class="p">-></span><span class="w"> </span><span class="n">'cR</span><span class="p">)</span><span class="w"> </span><span class="p">-></span><span class="w"> </span><span class="n">'c</span><span class="w"></span>\r | |
117 | <span class="k">end</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">struct</span><span class="w"></span>\r | |
118 | <span class="w"> </span><span class="k">type</span><span class="w"> </span><span class="p">(</span><span class="n">'dL</span><span class="p">,</span><span class="w"> </span><span class="n">'cL</span><span class="p">,</span><span class="w"> </span><span class="n">'dR</span><span class="p">,</span><span class="w"> </span><span class="n">'cR</span><span class="p">,</span><span class="w"> </span><span class="n">'c</span><span class="p">)</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">(</span><span class="n">'dL</span><span class="w"> </span><span class="p">-></span><span class="w"> </span><span class="n">'cL</span><span class="p">)</span><span class="w"> </span><span class="n">*</span><span class="w"> </span><span class="p">(</span><span class="n">'dR</span><span class="w"> </span><span class="p">-></span><span class="w"> </span><span class="n">'cR</span><span class="p">)</span><span class="w"> </span><span class="p">-></span><span class="w"> </span><span class="n">'c</span><span class="w"></span>\r | |
119 | <span class="w"> </span><span class="k">open</span><span class="w"> </span><span class="n">StaticSum</span><span class="w"></span>\r | |
120 | <span class="k">end</span><span class="w"></span>\r | |
121 | </pre></div></div></div>\r | |
122 | <div class="paragraph"><p>Above, <span class="monospaced">'d</span> stands for domain and <span class="monospaced">'c</span> for codomain. The key\r | |
123 | difference between an ordinary sum type, like <span class="monospaced">(int, real) Sum.t</span>, and\r | |
124 | a static sum type, like <span class="monospaced">(int, real, real, int, real) StaticSum.t</span>, is\r | |
125 | that the ordinary sum type says nothing about the type of the result\r | |
126 | of deconstructing a sum while the static sum type specifies the type.</p></div>\r | |
127 | <div class="paragraph"><p>With the sealed static sum module, we get the type</p></div>\r | |
128 | <div class="listingblock">\r | |
129 | <div class="content"><div class="highlight"><pre><span class="k">val</span><span class="w"> </span><span class="n">succ</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">int</span><span class="p">,</span><span class="w"> </span><span class="n">int</span><span class="p">,</span><span class="w"> </span><span class="n">real</span><span class="p">,</span><span class="w"> </span><span class="n">real</span><span class="p">,</span><span class="w"> </span><span class="n">'a</span><span class="p">)</span><span class="w"> </span><span class="n">StaticSum</span><span class="p">.</span><span class="n">t</span><span class="w"> </span><span class="p">-></span><span class="w"> </span><span class="n">'a</span><span class="w"></span>\r | |
130 | </pre></div></div></div>\r | |
131 | <div class="paragraph"><p>for the previously defined <span class="monospaced">succ</span> function. The type specifies that\r | |
132 | <span class="monospaced">succ</span> maps a left <span class="monospaced">int</span> to an <span class="monospaced">int</span> and a right <span class="monospaced">real</span> to a <span class="monospaced">real</span>.\r | |
133 | For example, the type of <span class="monospaced">StaticSum.inL 1</span> is\r | |
134 | <span class="monospaced">(int, 'cL, 'dR, 'cR, 'cL) StaticSum.t</span>. Unifying this with the\r | |
135 | argument type of <span class="monospaced">succ</span> gives the type <span class="monospaced">(int, int, real, real, int)\r | |
136 | StaticSum.t -> int</span>.</p></div>\r | |
137 | <div class="paragraph"><p>The <span class="monospaced">out</span> function is quite useful on its own. Here is how it can be\r | |
138 | defined:</p></div>\r | |
139 | <div class="listingblock">\r | |
140 | <div class="content"><div class="highlight"><pre><span class="k">structure</span><span class="w"> </span><span class="n">StaticSum</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">struct</span><span class="w"></span>\r | |
141 | <span class="w"> </span><span class="k">open</span><span class="w"> </span><span class="n">StaticSum</span><span class="w"></span>\r | |
142 | <span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">out</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">'a</span><span class="p">,</span><span class="w"> </span><span class="n">'a</span><span class="p">,</span><span class="w"> </span><span class="n">'b</span><span class="p">,</span><span class="w"> </span><span class="n">'b</span><span class="p">,</span><span class="w"> </span><span class="n">'c</span><span class="p">)</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="p">-></span><span class="w"> </span><span class="n">'c</span><span class="w"> </span><span class="p">=</span><span class="w"></span>\r | |
143 | <span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">match</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w"></span>\r | |
144 | <span class="k">end</span><span class="w"></span>\r | |
145 | </pre></div></div></div>\r | |
146 | <div class="paragraph"><p>Due to the value restriction, lack of first class polymorphism and\r | |
147 | polymorphic recursion, the usefulness and convenience of static sums\r | |
148 | is somewhat limited in SML. So, don’t throw away the ordinary sum\r | |
149 | type just yet. Static sums can nevertheless be quite useful.</p></div>\r | |
150 | <div class="sect2">\r | |
151 | <h3 id="_example_send_and_receive_with_argument_type_dependent_result_types">Example: Send and Receive with Argument Type Dependent Result Types</h3>\r | |
152 | <div class="paragraph"><p>In some situations it would seem useful to define functions whose\r | |
153 | result type would depend on some of the arguments. Traditionally such\r | |
154 | functions have been thought to be impossible in SML and the solution\r | |
155 | has been to define multiple functions. For example, the\r | |
156 | <a href="http://www.standardml.org/Basis/socket.html"><span class="monospaced">Socket</span> structure</a> of the\r | |
157 | Basis library defines 16 <span class="monospaced">send</span> and 16 <span class="monospaced">recv</span> functions. In contrast,\r | |
158 | the Net structure\r | |
159 | (<a href="https://github.com/MLton/mltonlib/blob/master/com/sweeks/basic/unstable/net.sig"><span class="monospaced">net.sig</span></a>) of the\r | |
160 | Basic library designed by Stephen Weeks defines only a single <span class="monospaced">send</span>\r | |
161 | and a single <span class="monospaced">receive</span> and the result types of the functions depend on\r | |
162 | their arguments. The implementation\r | |
163 | (<a href="https://github.com/MLton/mltonlib/blob/master/com/sweeks/basic/unstable/net.sml"><span class="monospaced">net.sml</span></a>) uses\r | |
164 | static sums (with a slighly different signature:\r | |
165 | <a href="https://github.com/MLton/mltonlib/blob/master/com/sweeks/basic/unstable/static-sum.sig"><span class="monospaced">static-sum.sig</span></a>).</p></div>\r | |
166 | </div>\r | |
167 | <div class="sect2">\r | |
168 | <h3 id="_example_picking_monad_results">Example: Picking Monad Results</h3>\r | |
169 | <div class="paragraph"><p>Suppose that we need to write a parser that accepts a pair of integers\r | |
170 | and returns their sum given a monadic parsing combinator library. A\r | |
171 | part of the signature of such library could look like this</p></div>\r | |
172 | <div class="listingblock">\r | |
173 | <div class="content"><div class="highlight"><pre><span class="k">signature</span><span class="w"> </span><span class="n">PARSING</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">sig</span><span class="w"></span>\r | |
174 | <span class="w"> </span><span class="k">include</span><span class="w"> </span><span class="n">MONAD</span><span class="w"></span>\r | |
175 | <span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">int</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">int</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r | |
176 | <span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">lparen</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">unit</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r | |
177 | <span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">rparen</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">unit</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r | |
178 | <span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">comma</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">unit</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r | |
179 | <span class="w"> </span><span class="cm">(* ... *)</span><span class="w"></span>\r | |
180 | <span class="k">end</span><span class="w"></span>\r | |
181 | </pre></div></div></div>\r | |
182 | <div class="paragraph"><p>where the <span class="monospaced">MONAD</span> signature could be defined as</p></div>\r | |
183 | <div class="listingblock">\r | |
184 | <div class="content"><div class="highlight"><pre><span class="k">signature</span><span class="w"> </span><span class="n">MONAD</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">sig</span><span class="w"></span>\r | |
185 | <span class="w"> </span><span class="k">type</span><span class="w"> </span><span class="n">'a</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r | |
186 | <span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">return</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">'a</span><span class="w"> </span><span class="p">-></span><span class="w"> </span><span class="n">'a</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r | |
187 | <span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">>>=</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">'a</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="n">*</span><span class="w"> </span><span class="p">(</span><span class="n">'a</span><span class="w"> </span><span class="p">-></span><span class="w"> </span><span class="n">'b</span><span class="w"> </span><span class="n">t</span><span class="p">)</span><span class="w"> </span><span class="p">-></span><span class="w"> </span><span class="n">'b</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r | |
188 | <span class="k">end</span><span class="w"></span>\r | |
189 | <span class="k">infix</span><span class="w"> </span><span class="n">>>=</span><span class="w"></span>\r | |
190 | </pre></div></div></div>\r | |
191 | <div class="paragraph"><p>The straightforward, but tedious, way to write the desired parser is:</p></div>\r | |
192 | <div class="listingblock">\r | |
193 | <div class="content"><div class="highlight"><pre><span class="k">val</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">lparen</span><span class="w"> </span><span class="n">>>=</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=></span><span class="w"></span>\r | |
194 | <span class="w"> </span><span class="n">int</span><span class="w"> </span><span class="n">>>=</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">=></span><span class="w"></span>\r | |
195 | <span class="w"> </span><span class="n">comma</span><span class="w"> </span><span class="n">>>=</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=></span><span class="w"></span>\r | |
196 | <span class="w"> </span><span class="n">int</span><span class="w"> </span><span class="n">>>=</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="p">=></span><span class="w"></span>\r | |
197 | <span class="w"> </span><span class="n">rparen</span><span class="w"> </span><span class="n">>>=</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=></span><span class="w"></span>\r | |
198 | <span class="w"> </span><span class="n">return</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="n">+</span><span class="w"> </span><span class="n">y</span><span class="p">))))))</span><span class="w"></span>\r | |
199 | </pre></div></div></div>\r | |
200 | <div class="paragraph"><p>In Haskell, the parser could be written using the <span class="monospaced">do</span> notation\r | |
201 | considerably less verbosely as:</p></div>\r | |
202 | <div class="listingblock">\r | |
203 | <div class="content"><div class="highlight"><pre><span class="nf">p</span> <span class="ow">=</span> <span class="kr">do</span> <span class="p">{</span> <span class="n">lparen</span> <span class="p">;</span> <span class="n">x</span> <span class="ow"><-</span> <span class="n">int</span> <span class="p">;</span> <span class="n">comma</span> <span class="p">;</span> <span class="n">y</span> <span class="ow"><-</span> <span class="n">int</span> <span class="p">;</span> <span class="n">rparen</span> <span class="p">;</span> <span class="n">return</span> <span class="o">$</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span> <span class="p">}</span>\r | |
204 | </pre></div></div></div>\r | |
205 | <div class="paragraph"><p>SML doesn’t provide a <span class="monospaced">do</span> notation, so we need another solution.</p></div>\r | |
206 | <div class="paragraph"><p>Suppose we would have a "pick" notation for monads that would allows\r | |
207 | us to write the parser as</p></div>\r | |
208 | <div class="listingblock">\r | |
209 | <div class="content"><div class="highlight"><pre><span class="k">val</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">`lparen</span><span class="w"> </span><span class="n">^</span><span class="w"> </span><span class="n">\int</span><span class="w"> </span><span class="n">^</span><span class="w"> </span><span class="n">`comma</span><span class="w"> </span><span class="n">^</span><span class="w"> </span><span class="n">\int</span><span class="w"> </span><span class="n">^</span><span class="w"> </span><span class="n">`rparen</span><span class="w"> </span><span class="n">@</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">&</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">+</span><span class="w"> </span><span class="n">y</span><span class="p">)</span><span class="w"></span>\r | |
210 | </pre></div></div></div>\r | |
211 | <div class="paragraph"><p>using four auxiliary combinators: <span class="monospaced">`</span>, <span class="monospaced">\</span>, <span class="monospaced">^</span>, and <span class="monospaced">@</span>.</p></div>\r | |
212 | <div class="paragraph"><p>Roughly speaking</p></div>\r | |
213 | <div class="ulist"><ul>\r | |
214 | <li>\r | |
215 | <p>\r | |
216 | <span class="monospaced">`p</span> means that the result of <span class="monospaced">p</span> is dropped,\r | |
217 | </p>\r | |
218 | </li>\r | |
219 | <li>\r | |
220 | <p>\r | |
221 | <span class="monospaced">\p</span> means that the result of <span class="monospaced">p</span> is taken,\r | |
222 | </p>\r | |
223 | </li>\r | |
224 | <li>\r | |
225 | <p>\r | |
226 | <span class="monospaced">p ^ q</span> means that results of <span class="monospaced">p</span> and <span class="monospaced">q</span> are taken as a product, and\r | |
227 | </p>\r | |
228 | </li>\r | |
229 | <li>\r | |
230 | <p>\r | |
231 | <span class="monospaced">p @ a</span> means that the results of <span class="monospaced">p</span> are passed to the function <span class="monospaced">a</span> and that result is returned.\r | |
232 | </p>\r | |
233 | </li>\r | |
234 | </ul></div>\r | |
235 | <div class="paragraph"><p>The difficulty is in implementing the concatenation combinator <span class="monospaced">^</span>.\r | |
236 | The type of the result of the concatenation depends on the types of\r | |
237 | the arguments.</p></div>\r | |
238 | <div class="paragraph"><p>Using static sums and the <a href="ProductType">product type</a>, the pick\r | |
239 | notation for monads can be implemented as follows:</p></div>\r | |
240 | <div class="listingblock">\r | |
241 | <div class="content"><div class="highlight"><pre><span class="k">functor</span><span class="w"> </span><span class="n">MkMonadPick</span><span class="w"> </span><span class="p">(</span><span class="k">include</span><span class="w"> </span><span class="n">MONAD</span><span class="p">)</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">let</span><span class="w"></span>\r | |
242 | <span class="w"> </span><span class="k">open</span><span class="w"> </span><span class="n">StaticSum</span><span class="w"></span>\r | |
243 | <span class="k">in</span><span class="w"></span>\r | |
244 | <span class="w"> </span><span class="k">struct</span><span class="w"></span>\r | |
245 | <span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">`a</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">inL</span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="n">>>=</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">return</span><span class="w"> </span><span class="p">()))</span><span class="w"></span>\r | |
246 | <span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">\</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">inR</span><span class="w"></span>\r | |
247 | <span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">@</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">out</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">>>=</span><span class="w"> </span><span class="p">(</span><span class="n">return</span><span class="w"> </span><span class="n">o</span><span class="w"> </span><span class="n">f</span><span class="p">)</span><span class="w"></span>\r | |
248 | <span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">^</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">=</span><span class="w"></span>\r | |
249 | <span class="w"> </span><span class="p">(</span><span class="n">match</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="n">o</span><span class="w"> </span><span class="n">match</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"></span>\r | |
250 | <span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">=></span><span class="w"></span>\r | |
251 | <span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">inL</span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="n">>>=</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">b</span><span class="p">)),</span><span class="w"></span>\r | |
252 | <span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">inR</span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="n">>>=</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">b</span><span class="p">))),</span><span class="w"></span>\r | |
253 | <span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">=></span><span class="w"></span>\r | |
254 | <span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">inR</span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="n">>>=</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="n">>>=</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">return</span><span class="w"> </span><span class="n">a</span><span class="p">))),</span><span class="w"></span>\r | |
255 | <span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">inR</span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="n">>>=</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="n">>>=</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">return</span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="n">&</span><span class="w"> </span><span class="n">b</span><span class="p">))))))</span><span class="w"></span>\r | |
256 | <span class="w"> </span><span class="k">end</span><span class="w"></span>\r | |
257 | <span class="k">end</span><span class="w"></span>\r | |
258 | </pre></div></div></div>\r | |
259 | <div class="paragraph"><p>The above implementation is inefficient, however. It uses many more\r | |
260 | bind operations, <span class="monospaced">>>=</span>, than necessary. That can be solved with an\r | |
261 | additional level of abstraction:</p></div>\r | |
262 | <div class="listingblock">\r | |
263 | <div class="content"><div class="highlight"><pre><span class="k">functor</span><span class="w"> </span><span class="n">MkMonadPick</span><span class="w"> </span><span class="p">(</span><span class="k">include</span><span class="w"> </span><span class="n">MONAD</span><span class="p">)</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">let</span><span class="w"></span>\r | |
264 | <span class="w"> </span><span class="k">open</span><span class="w"> </span><span class="n">StaticSum</span><span class="w"></span>\r | |
265 | <span class="k">in</span><span class="w"></span>\r | |
266 | <span class="w"> </span><span class="k">struct</span><span class="w"></span>\r | |
267 | <span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">`a</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">inL</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">>>=</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">()))</span><span class="w"></span>\r | |
268 | <span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">\a</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">inR</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">>>=</span><span class="w"> </span><span class="n">b</span><span class="p">)</span><span class="w"></span>\r | |
269 | <span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">@</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">out</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">(</span><span class="n">return</span><span class="w"> </span><span class="n">o</span><span class="w"> </span><span class="n">f</span><span class="p">)</span><span class="w"></span>\r | |
270 | <span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">^</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">=</span><span class="w"></span>\r | |
271 | <span class="w"> </span><span class="p">(</span><span class="n">match</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="n">o</span><span class="w"> </span><span class="n">match</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"></span>\r | |
272 | <span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">inL</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="n">c</span><span class="p">)),</span><span class="w"></span>\r | |
273 | <span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">inR</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="n">c</span><span class="p">))),</span><span class="w"></span>\r | |
274 | <span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">inR</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="n">a</span><span class="p">))),</span><span class="w"></span>\r | |
275 | <span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">inR</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="w"> </span><span class="n">&</span><span class="w"> </span><span class="n">b</span><span class="p">))))))</span><span class="w"></span>\r | |
276 | <span class="w"> </span><span class="k">end</span><span class="w"></span>\r | |
277 | <span class="k">end</span><span class="w"></span>\r | |
278 | </pre></div></div></div>\r | |
279 | <div class="paragraph"><p>After instantiating and opening either of the above monad pick\r | |
280 | implementations, the previously given definition of <span class="monospaced">p</span> can be\r | |
281 | compiled and results in a parser whose result is of type <span class="monospaced">int</span>. Here\r | |
282 | is a functor to test the theory:</p></div>\r | |
283 | <div class="listingblock">\r | |
284 | <div class="content"><div class="highlight"><pre><span class="k">functor</span><span class="w"> </span><span class="n">Test</span><span class="w"> </span><span class="p">(</span><span class="n">Arg</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">PARSING</span><span class="p">)</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">struct</span><span class="w"></span>\r | |
285 | <span class="w"> </span><span class="k">local</span><span class="w"></span>\r | |
286 | <span class="w"> </span><span class="k">structure</span><span class="w"> </span><span class="n">Pick</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">MkMonadPick</span><span class="w"> </span><span class="p">(</span><span class="n">Arg</span><span class="p">)</span><span class="w"></span>\r | |
287 | <span class="w"> </span><span class="k">open</span><span class="w"> </span><span class="n">Pick</span><span class="w"> </span><span class="n">Arg</span><span class="w"></span>\r | |
288 | <span class="w"> </span><span class="k">in</span><span class="w"></span>\r | |
289 | <span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">int</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="p">=</span><span class="w"></span>\r | |
290 | <span class="w"> </span><span class="n">`lparen</span><span class="w"> </span><span class="n">^</span><span class="w"> </span><span class="n">\int</span><span class="w"> </span><span class="n">^</span><span class="w"> </span><span class="n">`comma</span><span class="w"> </span><span class="n">^</span><span class="w"> </span><span class="n">\int</span><span class="w"> </span><span class="n">^</span><span class="w"> </span><span class="n">`rparen</span><span class="w"> </span><span class="n">@</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">&</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">+</span><span class="w"> </span><span class="n">y</span><span class="p">)</span><span class="w"></span>\r | |
291 | <span class="w"> </span><span class="k">end</span><span class="w"></span>\r | |
292 | <span class="k">end</span><span class="w"></span>\r | |
293 | </pre></div></div></div>\r | |
294 | </div>\r | |
295 | </div>\r | |
296 | </div>\r | |
297 | <div class="sect1">\r | |
298 | <h2 id="_also_see">Also see</h2>\r | |
299 | <div class="sectionbody">\r | |
300 | <div class="paragraph"><p>There are a number of related techniques. Here are some of them.</p></div>\r | |
301 | <div class="ulist"><ul>\r | |
302 | <li>\r | |
303 | <p>\r | |
304 | <a href="Fold">Fold</a>\r | |
305 | </p>\r | |
306 | </li>\r | |
307 | <li>\r | |
308 | <p>\r | |
309 | <a href="TypeIndexedValues">TypeIndexedValues</a>\r | |
310 | </p>\r | |
311 | </li>\r | |
312 | </ul></div>\r | |
313 | </div>\r | |
314 | </div>\r | |
315 | </div>\r | |
316 | <div id="footnotes"><hr></div>\r | |
317 | <div id="footer">\r | |
318 | <div id="footer-text">\r | |
319 | </div>\r | |
320 | <div id="footer-badges">\r | |
321 | </div>\r | |
322 | </div>\r | |
323 | </body>\r | |
324 | </html>\r |