Import Debian changes 20180207-1
[hcoop/debian/mlton.git] / doc / guide / localhost / VariableArityPolymorphism
CommitLineData
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>VariableArityPolymorphism</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
14asciidoc.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>VariableArityPolymorphism</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><a href="StandardML">Standard ML</a> programmers often face the problem of how to\r
32provide a variable-arity polymorphic function. For example, suppose\r
33one is defining a combinator library, e.g. for parsing or pickling.\r
34The signature for such a library might look something like the\r
35following.</p></div>\r
36<div class="listingblock">\r
37<div class="content"><div class="highlight"><pre><span class="k">signature</span><span class="w"> </span><span class="n">COMBINATOR</span><span class="w"> </span><span class="p">=</span><span class="w"></span>\r
38<span class="w"> </span><span class="k">sig</span><span class="w"></span>\r
39<span class="w"> </span><span class="k">type</span><span class="w"> </span><span class="n">&#39;a</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r
40\r
41<span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">int</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
42<span class="w"> </span><span class="k">val</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="w"> </span><span class="n">t</span><span class="w"></span>\r
43<span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">string</span><span class="p">:</span><span class="w"> </span><span class="n">string</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r
44<span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">unit</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
45<span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">tuple2</span><span class="p">:</span><span class="w"> </span><span class="n">&#39;a1</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="n">*</span><span class="w"> </span><span class="n">&#39;a2</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="p">(</span><span class="n">&#39;a1</span><span class="w"> </span><span class="n">*</span><span class="w"> </span><span class="n">&#39;a2</span><span class="p">)</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r
46<span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">tuple3</span><span class="p">:</span><span class="w"> </span><span class="n">&#39;a1</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="n">*</span><span class="w"> </span><span class="n">&#39;a2</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="n">*</span><span class="w"> </span><span class="n">&#39;a3</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="p">(</span><span class="n">&#39;a1</span><span class="w"> </span><span class="n">*</span><span class="w"> </span><span class="n">&#39;a2</span><span class="w"> </span><span class="n">*</span><span class="w"> </span><span class="n">&#39;a3</span><span class="p">)</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r
47<span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">tuple4</span><span class="p">:</span><span class="w"> </span><span class="n">&#39;a1</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="n">*</span><span class="w"> </span><span class="n">&#39;a2</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="n">*</span><span class="w"> </span><span class="n">&#39;a3</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="n">*</span><span class="w"> </span><span class="n">&#39;a4</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r
48<span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="p">(</span><span class="n">&#39;a1</span><span class="w"> </span><span class="n">*</span><span class="w"> </span><span class="n">&#39;a2</span><span class="w"> </span><span class="n">*</span><span class="w"> </span><span class="n">&#39;a3</span><span class="w"> </span><span class="n">*</span><span class="w"> </span><span class="n">&#39;a4</span><span class="p">)</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r
49<span class="w"> </span><span class="p">...</span><span class="w"></span>\r
50<span class="w"> </span><span class="k">end</span><span class="w"></span>\r
51</pre></div></div></div>\r
52<div class="paragraph"><p>The question is how to define a variable-arity tuple combinator.\r
53Traditionally, the only way to take a variable number of arguments in\r
54SML is to put the arguments in a list (or vector) and pass that. So,\r
55one might define a tuple combinator with the following signature.</p></div>\r
56<div class="listingblock">\r
57<div class="content"><div class="highlight"><pre><span class="k">val</span><span class="w"> </span><span class="n">tupleN</span><span class="p">:</span><span class="w"> </span><span class="n">&#39;a</span><span class="w"> </span><span class="n">list</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">&#39;a</span><span class="w"> </span><span class="n">list</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r
58</pre></div></div></div>\r
59<div class="paragraph"><p>The problem with this approach is that as soon as one places values in\r
60a list, they must all have the same type. So, programmers often take\r
61an alternative approach, and define a family of <span class="monospaced">tuple&lt;N&gt;</span> functions,\r
62as we see in the <span class="monospaced">COMBINATOR</span> signature above.</p></div>\r
63<div class="paragraph"><p>The family-of-functions approach is ugly for many reasons. First, it\r
64clutters the signature with a number of functions when there should\r
65really only be one. Second, it is <em>closed</em>, in that there are a fixed\r
66number of tuple combinators in the interface, and should a client need\r
67a combinator for a large tuple, he is out of luck. Third, this\r
68approach often requires a lot of duplicate code in the implementation\r
69of the combinators.</p></div>\r
70<div class="paragraph"><p>Fortunately, using <a href="Fold01N">Fold01N</a> and <a href="ProductType">products</a>, one can\r
71provide an interface and implementation that solves all these\r
72problems. Here is a simple pickling module that converts values to\r
73strings.</p></div>\r
74<div class="listingblock">\r
75<div class="content"><div class="highlight"><pre><span class="k">structure</span><span class="w"> </span><span class="n">Pickler</span><span class="w"> </span><span class="p">=</span><span class="w"></span>\r
76<span class="w"> </span><span class="k">struct</span><span class="w"></span>\r
77<span class="w"> </span><span class="k">type</span><span class="w"> </span><span class="n">&#39;a</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">&#39;a</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">string</span><span class="w"></span>\r
78\r
79<span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">unit</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="w"></span>\r
80\r
81<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="p">.</span><span class="n">toString</span><span class="w"></span>\r
82\r
83<span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">real</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">toString</span><span class="w"></span>\r
84\r
85<span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">string</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">id</span><span class="w"></span>\r
86\r
87<span class="w"> </span><span class="k">type</span><span class="w"> </span><span class="n">&#39;a</span><span class="w"> </span><span class="n">accum</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">&#39;a</span><span class="w"> </span><span class="n">*</span><span class="w"> </span><span class="n">string</span><span class="w"> </span><span class="n">list</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">string</span><span class="w"> </span><span class="n">list</span><span class="w"></span>\r
88\r
89<span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">tuple</span><span class="w"> </span><span class="p">=</span><span class="w"></span>\r
90<span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>\r
91<span class="w"> </span><span class="n">Fold01N</span><span class="p">.</span><span class="n">fold</span><span class="w"></span>\r
92<span class="w"> </span><span class="p">{</span><span class="n">finish</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">ps</span><span class="w"> </span><span class="p">=&gt;</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">=&gt;</span><span class="w"> </span><span class="n">concat</span><span class="w"> </span><span class="p">(</span><span class="n">rev</span><span class="w"> </span><span class="p">(</span><span class="n">ps</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="p">[]))),</span><span class="w"></span>\r
93<span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">l</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">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">l</span><span class="p">,</span><span class="w"></span>\r
94<span class="w"> </span><span class="n">zero</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">unit</span><span class="p">}</span><span class="w"></span>\r
95<span class="w"> </span><span class="n">z</span><span class="w"></span>\r
96\r
97<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>\r
98<span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>\r
99<span class="w"> </span><span class="n">Fold01N</span><span class="p">.</span><span class="n">step1</span><span class="w"></span>\r
100<span class="w"> </span><span class="p">{</span><span class="n">combine</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="p">(</span><span class="n">p</span><span class="p">,</span><span class="w"> </span><span class="n">p&#39;</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="n">&amp;</span><span class="w"> </span><span class="n">x&#39;</span><span class="p">,</span><span class="w"> </span><span class="n">l</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">p&#39;</span><span class="w"> </span><span class="n">x&#39;</span><span class="w"> </span><span class="n">::</span><span class="w"> </span><span class="s">&quot;,&quot;</span><span class="w"> </span><span class="n">::</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">l</span><span class="p">))}</span><span class="w"></span>\r
101<span class="w"> </span><span class="n">z</span><span class="w"></span>\r
102<span class="w"> </span><span class="k">end</span><span class="w"></span>\r
103</pre></div></div></div>\r
104<div class="paragraph"><p>If one has <span class="monospaced">n</span> picklers of types</p></div>\r
105<div class="listingblock">\r
106<div class="content"><div class="highlight"><pre><span class="k">val</span><span class="w"> </span><span class="n">p1</span><span class="p">:</span><span class="w"> </span><span class="n">a1</span><span class="w"> </span><span class="n">Pickler</span><span class="p">.</span><span class="n">t</span><span class="w"></span>\r
107<span class="k">val</span><span class="w"> </span><span class="n">p2</span><span class="p">:</span><span class="w"> </span><span class="n">a2</span><span class="w"> </span><span class="n">Pickler</span><span class="p">.</span><span class="n">t</span><span class="w"></span>\r
108<span class="p">...</span><span class="w"></span>\r
109<span class="k">val</span><span class="w"> </span><span class="n">pn</span><span class="p">:</span><span class="w"> </span><span class="n">an</span><span class="w"> </span><span class="n">Pickler</span><span class="p">.</span><span class="n">t</span><span class="w"></span>\r
110</pre></div></div></div>\r
111<div class="paragraph"><p>then one can construct a pickler for n-ary products as follows.</p></div>\r
112<div class="listingblock">\r
113<div class="content"><div class="highlight"><pre><span class="n">tuple</span><span class="w"> </span><span class="n">`p1</span><span class="w"> </span><span class="n">`p2</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="n">`pn</span><span class="w"> </span><span class="n">$</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">a1</span><span class="w"> </span><span class="n">&amp;</span><span class="w"> </span><span class="n">a2</span><span class="w"> </span><span class="n">&amp;</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="n">&amp;</span><span class="w"> </span><span class="n">an</span><span class="p">)</span><span class="w"> </span><span class="n">Pickler</span><span class="p">.</span><span class="n">t</span><span class="w"></span>\r
114</pre></div></div></div>\r
115<div class="paragraph"><p>For example, with <span class="monospaced">Pickler</span> in scope, one can prove the following\r
116equations.</p></div>\r
117<div class="listingblock">\r
118<div class="content"><div class="highlight"><pre><span class="s">&quot;&quot;</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">tuple</span><span class="w"> </span><span class="n">$</span><span class="w"> </span><span class="p">()</span><span class="w"></span>\r
119<span class="s">&quot;1&quot;</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">tuple</span><span class="w"> </span><span class="n">`int</span><span class="w"> </span><span class="n">$</span><span class="w"> </span><span class="mi">1</span><span class="w"></span>\r
120<span class="s">&quot;1,2.0&quot;</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">tuple</span><span class="w"> </span><span class="n">`int</span><span class="w"> </span><span class="n">`real</span><span class="w"> </span><span class="n">$</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="w"> </span><span class="n">&amp;</span><span class="w"> </span><span class="mf">2.0</span><span class="p">)</span><span class="w"></span>\r
121<span class="s">&quot;1,2.0,three&quot;</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">tuple</span><span class="w"> </span><span class="n">`int</span><span class="w"> </span><span class="n">`real</span><span class="w"> </span><span class="n">`string</span><span class="w"> </span><span class="n">$</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="w"> </span><span class="n">&amp;</span><span class="w"> </span><span class="mf">2.0</span><span class="w"> </span><span class="n">&amp;</span><span class="w"> </span><span class="s">&quot;three&quot;</span><span class="p">)</span><span class="w"></span>\r
122</pre></div></div></div>\r
123<div class="paragraph"><p>Here is the signature for <span class="monospaced">Pickler</span>. It shows why the <span class="monospaced">accum</span> type is\r
124useful.</p></div>\r
125<div class="listingblock">\r
126<div class="content"><div class="highlight"><pre><span class="k">signature</span><span class="w"> </span><span class="n">PICKLER</span><span class="w"> </span><span class="p">=</span><span class="w"></span>\r
127<span class="w"> </span><span class="k">sig</span><span class="w"></span>\r
128<span class="w"> </span><span class="k">type</span><span class="w"> </span><span class="n">&#39;a</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r
129\r
130<span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">int</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
131<span class="w"> </span><span class="k">val</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="w"> </span><span class="n">t</span><span class="w"></span>\r
132<span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">string</span><span class="p">:</span><span class="w"> </span><span class="n">string</span><span class="w"> </span><span class="n">t</span><span class="w"></span>\r
133<span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">unit</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
134\r
135<span class="w"> </span><span class="k">type</span><span class="w"> </span><span class="n">&#39;a</span><span class="w"> </span><span class="n">accum</span><span class="w"></span>\r
136<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="p">(</span><span class="n">&#39;a</span><span class="w"> </span><span class="n">accum</span><span class="p">,</span><span class="w"> </span><span class="n">&#39;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="n">&#39;a</span><span class="p">,</span><span class="w"> </span><span class="n">&#39;b</span><span class="p">)</span><span class="w"> </span><span class="n">prod</span><span class="w"> </span><span class="n">accum</span><span class="p">,</span><span class="w"></span>\r
137<span class="w"> </span><span class="n">&#39;z1</span><span class="p">,</span><span class="w"> </span><span class="n">&#39;z2</span><span class="p">,</span><span class="w"> </span><span class="n">&#39;z3</span><span class="p">,</span><span class="w"> </span><span class="n">&#39;z4</span><span class="p">,</span><span class="w"> </span><span class="n">&#39;z5</span><span class="p">,</span><span class="w"> </span><span class="n">&#39;z6</span><span class="p">,</span><span class="w"> </span><span class="n">&#39;z7</span><span class="p">)</span><span class="w"> </span><span class="n">Fold01N</span><span class="p">.</span><span class="n">step1</span><span class="w"></span>\r
138<span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">tuple</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">&#39;a</span><span class="w"> </span><span class="n">t</span><span class="p">,</span><span class="w"> </span><span class="n">&#39;a</span><span class="w"> </span><span class="n">accum</span><span class="p">,</span><span class="w"> </span><span class="n">&#39;b</span><span class="w"> </span><span class="n">accum</span><span class="p">,</span><span class="w"> </span><span class="n">&#39;b</span><span class="w"> </span><span class="n">t</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="p">,</span><span class="w"></span>\r
139<span class="w"> </span><span class="n">&#39;z1</span><span class="p">,</span><span class="w"> </span><span class="n">&#39;z2</span><span class="p">,</span><span class="w"> </span><span class="n">&#39;z3</span><span class="p">,</span><span class="w"> </span><span class="n">&#39;z4</span><span class="p">,</span><span class="w"> </span><span class="n">&#39;z5</span><span class="p">)</span><span class="w"> </span><span class="n">Fold01N</span><span class="p">.</span><span class="n">t</span><span class="w"></span>\r
140<span class="w"> </span><span class="k">end</span><span class="w"></span>\r
141\r
142<span class="k">structure</span><span class="w"> </span><span class="n">Pickler</span><span class="p">:</span><span class="w"> </span><span class="n">PICKLER</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Pickler</span><span class="w"></span>\r
143</pre></div></div></div>\r
144</div>\r
145</div>\r
146</div>\r
147<div id="footnotes"><hr></div>\r
148<div id="footer">\r
149<div id="footer-text">\r
150</div>\r
151<div id="footer-badges">\r
152</div>\r
153</div>\r
154</body>\r
155</html>\r