<!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>ArrayLiteral</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>ArrayLiteral</h1>
</div>
<div id="content">
<div class="paragraph">
<p><a href="StandardML">Standard ML</a> does not have a syntax for array literals or
vector literals.  The only way to write down an array is like</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="sml">Array.fromList [w, x, y, z]</code></pre>
</div>
</div>
<div class="paragraph">
<p>No SML compiler produces efficient code for the above expression.  The
generated code allocates a list and then converts it to an array.  To
alleviate this, one could write down the same array using
<code>Array.tabulate</code>, or even using <code>Array.array</code> and <code>Array.update</code>, but
that is syntactically unwieldy.</p>
</div>
<div class="paragraph">
<p>Fortunately, using <a href="Fold">Fold</a>, it is possible to define constants <code>A</code>,
and <code>`</code> so that one can write down an array like:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="sml">A `w `x `y `z $</code></pre>
</div>
</div>
<div class="paragraph">
<p>This is as syntactically concise as the <code>fromList</code> expression.
Furthermore, MLton, at least, will generate the efficient code as if
one had written down a use of <code>Array.array</code> followed by four uses of
<code>Array.update</code>.</p>
</div>
<div class="paragraph">
<p>Along with <code>A</code> and <code>`</code>, one can define a constant <code>V</code> that makes
it possible to define vector literals with the same syntax, e.g.,</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="sml">V `w `x `y `z $</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note that the same element indicator, <code>`</code>, serves for both array
and vector literals.  Of course, the <code>$</code> is the end-of-arguments
marker always used with <a href="Fold">Fold</a>.  The only difference between an
array literal and vector literal is the <code>A</code> or <code>V</code> at the beginning.</p>
</div>
<div class="paragraph">
<p>Here is the implementation of <code>A</code>, <code>V</code>, and <code>`</code>.  We place them
in a structure and use signature abstraction to hide the type of the
accumulator.  See <a href="Fold">Fold</a> for more on this technique.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="sml">structure Literal:&gt;
   sig
      type 'a z
      val A: ('a z, 'a z, 'a array, 'd) Fold.t
      val V: ('a z, 'a z, 'a vector, 'd) Fold.t
      val ` : ('a, 'a z, 'a z, 'b, 'c, 'd) Fold.step1
   end =
   struct
      type 'a z = int * 'a option * ('a array -&gt; unit)

      val A =
         fn z =&gt;
         Fold.fold
         ((0, NONE, ignore),
          fn (n, opt, fill) =&gt;
          case opt of
             NONE =&gt;
                Array.tabulate (0, fn _ =&gt; raise Fail "array0")
           | SOME x =&gt;
                let
                   val a = Array.array (n, x)
                   val () = fill a
                in
                   a
                end)
         z

      val V = fn z =&gt; Fold.post (A, Array.vector) z

      val ` =
         fn z =&gt;
         Fold.step1
         (fn (x, (i, opt, fill)) =&gt;
          (i + 1,
           SOME x,
           fn a =&gt; (Array.update (a, i, x); fill a)))
         z
   end</code></pre>
</div>
</div>
<div class="paragraph">
<p>The idea of the code is for the fold to accumulate a count of the
number of elements, a sample element, and a function that fills in all
the elements.  When the fold is complete, the finishing function
allocates the array, applies the fill function, and returns the array.
The only difference between <code>A</code> and <code>V</code> is at the very end; <code>A</code> just
returns the array, while <code>V</code> converts it to a vector using
post-composition, which is further described on the <a href="Fold">Fold</a> page.</p>
</div>
</div>
</body>
</html>