<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.26">
<title>VariableArityPolymorphism</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
<link rel="stylesheet" href="./asciidoctor.css">
<link rel="stylesheet" href="./mlton.css">

</head>
<body class="article">
<div id="mlton-header">
<div id="mlton-header-text">
<h2>
<a href="./Home">
MLton
20241230+git20251029+dfsg-5
</a>
</h2>
</div>
</div>
<div id="header">
<h1>VariableArityPolymorphism</h1>
</div>
<div id="content">
<div class="paragraph">
<p><a href="StandardML">Standard ML</a> programmers often face the problem of how to
provide a variable-arity polymorphic function.  For example, suppose
one is defining a combinator library, e.g. for parsing or pickling.
The signature for such a library might look something like the
following.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="sml">signature COMBINATOR =
   sig
      type 'a t

      val int: int t
      val real: real t
      val string: string t
      val unit: unit t
      val tuple2: 'a1 t * 'a2 t -&gt; ('a1 * 'a2) t
      val tuple3: 'a1 t * 'a2 t * 'a3 t -&gt; ('a1 * 'a2 * 'a3) t
      val tuple4: 'a1 t * 'a2 t * 'a3 t * 'a4 t
                  -&gt; ('a1 * 'a2 * 'a3 * 'a4) t
      ...
   end</code></pre>
</div>
</div>
<div class="paragraph">
<p>The question is how to define a variable-arity tuple combinator.
Traditionally, the only way to take a variable number of arguments in
SML is to put the arguments in a list (or vector) and pass that.  So,
one might define a tuple combinator with the following signature.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="sml">val tupleN: 'a list -&gt; 'a list t</code></pre>
</div>
</div>
<div class="paragraph">
<p>The problem with this approach is that as soon as one places values in
a list, they must all have the same type.  So, programmers often take
an alternative approach, and define a family of <code>tuple&lt;N&gt;</code> functions,
as we see in the <code>COMBINATOR</code> signature above.</p>
</div>
<div class="paragraph">
<p>The family-of-functions approach is ugly for many reasons.  First, it
clutters the signature with a number of functions when there should
really only be one.  Second, it is <em>closed</em>, in that there are a fixed
number of tuple combinators in the interface, and should a client need
a combinator for a large tuple, he is out of luck.  Third, this
approach often requires a lot of duplicate code in the implementation
of the combinators.</p>
</div>
<div class="paragraph">
<p>Fortunately, using <a href="Fold01N">Fold01N</a> and <a href="ProductType">products</a>, one can
provide an interface and implementation that solves all these
problems.  Here is a simple pickling module that converts values to
strings.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="sml">structure Pickler =
   struct
      type 'a t = 'a -&gt; string

      val unit = fn () =&gt; ""

      val int = Int.toString

      val real = Real.toString

      val string = id

      type 'a accum = 'a * string list -&gt; string list

      val tuple =
         fn z =&gt;
         Fold01N.fold
         {finish = fn ps =&gt; fn x =&gt; concat (rev (ps (x, []))),
          start = fn p =&gt; fn (x, l) =&gt; p x :: l,
          zero = unit}
         z

      val ` =
         fn z =&gt;
         Fold01N.step1
         {combine = (fn (p, p') =&gt; fn (x &amp; x', l) =&gt; p' x' :: "," :: p (x, l))}
         z
   end</code></pre>
</div>
</div>
<div class="paragraph">
<p>If one has <code>n</code> picklers of types</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="sml">val p1: a1 Pickler.t
val p2: a2 Pickler.t
...
val pn: an Pickler.t</code></pre>
</div>
</div>
<div class="paragraph">
<p>then one can construct a pickler for n-ary products as follows.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="sml">tuple `p1 `p2 ... `pn $ : (a1 &amp; a2 &amp; ... &amp; an) Pickler.t</code></pre>
</div>
</div>
<div class="paragraph">
<p>For example, with <code>Pickler</code> in scope, one can prove the following
equations.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="sml">"" = tuple $ ()
"1" = tuple `int $ 1
"1,2.0" = tuple `int `real $ (1 &amp; 2.0)
"1,2.0,three" = tuple `int `real `string $ (1 &amp; 2.0 &amp; "three")</code></pre>
</div>
</div>
<div class="paragraph">
<p>Here is the signature for <code>Pickler</code>.  It shows why the <code>accum</code> type is
useful.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="sml">signature PICKLER =
   sig
      type 'a t

      val int: int t
      val real: real t
      val string: string t
      val unit: unit t

      type 'a accum
      val ` : ('a accum, 'b t, ('a, 'b) prod accum,
               'z1, 'z2, 'z3, 'z4, 'z5, 'z6, 'z7) Fold01N.step1
      val tuple: ('a t, 'a accum, 'b accum, 'b t, unit t,
                  'z1, 'z2, 'z3, 'z4, 'z5) Fold01N.t
   end

structure Pickler: PICKLER = Pickler</code></pre>
</div>
</div>
</div>
</body>
</html>