<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="generator" content="AsciiDoc 8.6.10">
<title>MLtonContIsolateImplementation</title>
<link rel="stylesheet" href="./asciidoc.css" type="text/css">
<link rel="stylesheet" href="./pygments.css" type="text/css">


<script type="text/javascript" src="./asciidoc.js"></script>
<script type="text/javascript">
/*<![CDATA[*/
asciidoc.install();
/*]]>*/
</script>
<link rel="stylesheet" href="./mlton.css" type="text/css">
</head>
<body class="article">
<div id="banner">
<div id="banner-home">
<a href="./Home">MLton 20201002</a>
</div>
</div>
<div id="header">
<h1>MLtonContIsolateImplementation</h1>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph"><p>As noted before, it is fairly easy to get the operational behavior of <span class="monospaced">isolate</span> with just <span class="monospaced">callcc</span> and <span class="monospaced">throw</span>, but establishing the right space behavior is trickier.  Here, we show how to start from the obvious, but inefficient, implementation of <span class="monospaced">isolate</span> using only <span class="monospaced">callcc</span> and <span class="monospaced">throw</span>, and <em>derive</em> an equivalent, but more efficient, implementation of <span class="monospaced">isolate</span> using MLton&#8217;s primitive stack capture and copy operations.  This isn&#8217;t a formal derivation, as we are not formally showing the equivalence of the programs (though I believe that they are all equivalent, modulo the space behavior).</p></div>
<div class="paragraph"><p>Here is a direct implementation of isolate using only <span class="monospaced">callcc</span> and <span class="monospaced">throw</span>:</p></div>
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span></span><span class="k">val</span><span class="w"> </span><span class="n">isolate</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="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="p">)</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">t</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">  </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">f</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">unit</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">  </span><span class="n">callcc</span><span class="w"></span>
<span class="w">  </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">k1</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">   </span><span class="k">let</span><span class="w"></span>
<span class="w">      </span><span class="k">val</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">callcc</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">k2</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">throw</span><span class="w"> </span><span class="p">(</span><span class="n">k1</span><span class="p">,</span><span class="w"> </span><span class="n">k2</span><span class="p">))</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">(</span><span class="n">f</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">Exit</span><span class="p">.</span><span class="n">topLevelSuffix</span><span class="w"> </span><span class="p">())</span><span class="w"></span>
<span class="w">              </span><span class="k">handle</span><span class="w"> </span><span class="n">exn</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">MLtonExn</span><span class="p">.</span><span class="n">topLevelHandler</span><span class="w"> </span><span class="n">exn</span><span class="w"></span>
<span class="w">   </span><span class="k">in</span><span class="w"></span>
<span class="w">      </span><span class="k">raise</span><span class="w"> </span><span class="n">Fail</span><span class="w"> </span><span class="s">&quot;MLton.Cont.isolate: return from (wrapped) func&quot;</span><span class="w"></span>
<span class="w">   </span><span class="k">end</span><span class="p">)</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>We use the standard nested <span class="monospaced">callcc</span> trick to return a continuation that is ready to receive an argument, execute the isolated function, and exit the program.  Both <span class="monospaced">Exit.topLevelSuffix</span> and <span class="monospaced">MLtonExn.topLevelHandler</span> will terminate the program.</p></div>
<div class="paragraph"><p>Throwing to an isolated function will execute the function in a <em>semantically</em> empty context, in the sense that we never re-execute the <em>original</em> continuation of the call to isolate (i.e., the context that was in place at the time <span class="monospaced">isolate</span> was called).  However, we assume that the compiler isn&#8217;t able to recognize that the <em>original</em> continuation is unused; for example, while we (the programmer) know that <span class="monospaced">Exit.topLevelSuffix</span> and <span class="monospaced">MLtonExn.topLevelHandler</span> will terminate the program, the compiler may only see opaque calls to unknown foreign-functions.  So, that original continuation (in its entirety) is part of the continuation returned by <span class="monospaced">isolate</span> and throwing to the continuation returned by <span class="monospaced">isolate</span> will execute <span class="monospaced">f x</span> (with the exit wrapper) in the context of that original continuation.  Thus, the garbage collector will retain  everything reachable from that original continuation during the evaluation of <span class="monospaced">f x</span>, even though it is <em>semantically</em> garbage.</p></div>
<div class="paragraph"><p>Note that this space-leak is independent of the implementation of continuations (it arises in both MLton&#8217;s stack copying implementation of continuations and would arise in SML/NJ&#8217;s CPS-translation implementation); we are only assuming that the implementation can&#8217;t <em>see</em> the program termination, and so must retain the original continuation (and anything reachable from it).</p></div>
<div class="paragraph"><p>So, we need an <em>empty</em> continuation in which to execute <span class="monospaced">f x</span>.  (No surprise there, as that is the written description of <span class="monospaced">isolate</span>.)  To do this, we capture a top-level continuation and throw to that in order to execute <span class="monospaced">f x</span>:</p></div>
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span></span><span class="k">local</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">base</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">unit</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">unit</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="w">  </span><span class="n">callcc</span><span class="w"></span>
<span class="w">  </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">k1</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">   </span><span class="k">let</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="n">th</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">callcc</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">k2</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">throw</span><span class="w"> </span><span class="p">(</span><span class="n">k1</span><span class="p">,</span><span class="w"> </span><span class="n">k2</span><span class="p">))</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">(</span><span class="n">th</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">Exit</span><span class="p">.</span><span class="n">topLevelSuffix</span><span class="w"> </span><span class="p">())</span><span class="w"></span>
<span class="w">              </span><span class="k">handle</span><span class="w"> </span><span class="n">exn</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">MLtonExn</span><span class="p">.</span><span class="n">topLevelHandler</span><span class="w"> </span><span class="n">exn</span><span class="w"></span>
<span class="w">   </span><span class="k">in</span><span class="w"></span>
<span class="w">      </span><span class="k">raise</span><span class="w"> </span><span class="n">Fail</span><span class="w"> </span><span class="s">&quot;MLton.Cont.isolate: return from (wrapped) func&quot;</span><span class="w"></span>
<span class="w">   </span><span class="k">end</span><span class="p">)</span><span class="w"></span>
<span class="k">in</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">isolate</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="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="p">)</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">t</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">  </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">f</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">unit</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">  </span><span class="n">callcc</span><span class="w"></span>
<span class="w">  </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">k1</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">   </span><span class="k">let</span><span class="w"></span>
<span class="w">      </span><span class="k">val</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">callcc</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">k2</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">throw</span><span class="w"> </span><span class="p">(</span><span class="n">k1</span><span class="p">,</span><span class="w"> </span><span class="n">k2</span><span class="p">))</span><span class="w"></span>
<span class="w">   </span><span class="k">in</span><span class="w"></span>
<span class="w">      </span><span class="n">throw</span><span class="w"> </span><span class="p">(</span><span class="n">base</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="n">f</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w"></span>
<span class="w">   </span><span class="k">end</span><span class="p">)</span><span class="w"></span>
<span class="k">end</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>We presume that <span class="monospaced">base</span> is evaluated <em>early</em> in the program.  There is a subtlety here, because one needs to believe that this <span class="monospaced">base</span> continuation (which technically corresponds to the entire rest of the program evaluation) <em>works</em> as an empty context; in particular, we want it to be the case that executing <span class="monospaced">f x</span> in the <span class="monospaced">base</span> context retains less space than executing <span class="monospaced">f x</span> in the context in place at the call to <span class="monospaced">isolate</span> (as occurred in the previous implementation of <span class="monospaced">isolate</span>).  This isn&#8217;t particularly easy to believe if one takes a normal substitution-based operational semantics, because it seems that the context captured and bound to <span class="monospaced">base</span> is arbitrarily large.  However, this context is mostly unevaluated code; the only heap-allocated values that are reachable from it are those that were evaluated before the evaluation of <span class="monospaced">base</span> (and used in the program after the evaluation of <span class="monospaced">base</span>).  Assuming that <span class="monospaced">base</span> is evaluated <em>early</em> in the program, we conclude that there are few heap-allocated values reachable from its continuation.  In contrast, the previous implementation of <span class="monospaced">isolate</span> could capture a context that has many heap-allocated values reachable from it (because we could evaluate <span class="monospaced">isolate f</span> <em>late</em> in the program and <em>deep</em> in a call stack), which would all remain reachable during the evaluation of
<span class="monospaced">f x</span>.  [We&#8217;ll return to this point later, as it is taking a slightly MLton-esque view of the evaluation of a program, and may not apply as strongly to other implementations (e.g., SML/NJ).]</p></div>
<div class="paragraph"><p>Now, once we throw to <span class="monospaced">base</span> and begin executing <span class="monospaced">f x</span>, only the heap-allocated values reachable from <span class="monospaced">f</span> and <span class="monospaced">x</span> and the few heap-allocated values reachable from <span class="monospaced">base</span> are retained by the garbage collector.  So, it seems that <span class="monospaced">base</span> <em>works</em> as an empty context.</p></div>
<div class="paragraph"><p>But, what about the continuation returned from <span class="monospaced">isolate f</span>?  Note that the continuation returned by <span class="monospaced">isolate</span> is one that receives an argument <span class="monospaced">x</span> and then
throws to <span class="monospaced">base</span> to evaluate <span class="monospaced">f x</span>.  If we used a CPS-translation implementation (and assume sufficient beta-contractions to eliminate administrative redexes), then the original continuation passed to <span class="monospaced">isolate</span> (i.e., the continuation bound to <span class="monospaced">k1</span>) will not be free in the continuation returned by <span class="monospaced">isolate f</span>.  Rather, the only free variables in the continuation returned by <span class="monospaced">isolate f</span> will be <span class="monospaced">base</span> and <span class="monospaced">f</span>, so the only heap-allocated values reachable from the continuation returned by <span class="monospaced">isolate f</span> will be those values reachable from <span class="monospaced">base</span> (assumed to be few) and those values reachable from <span class="monospaced">f</span> (necessary in order to execute <span class="monospaced">f</span> at some later point).</p></div>
<div class="paragraph"><p>But, MLton doesn&#8217;t use a CPS-translation implementation.  Rather, at each call to <span class="monospaced">callcc</span> in the body of <span class="monospaced">isolate</span>, MLton will copy the current execution stack.  Thus, <span class="monospaced">k2</span> (the continuation returned by <span class="monospaced">isolate f</span>) will include execution stack at the time of the call to <span class="monospaced">isolate f</span>&#8201;&#8212;&#8201;that is, it will include the <em>original</em> continuation of the call to <span class="monospaced">isolate f</span>.  Thus, the heap-allocated values reachable from the continuation returned by <span class="monospaced">isolate f</span> will include those values reachable from <span class="monospaced">base</span>, those values reachable from <span class="monospaced">f</span>, and those values reachable from the original continuation of the call to <span class="monospaced">isolate f</span>.  So, just holding on to the continuation returned by <span class="monospaced">isolate f</span> will retain all of the heap-allocated values live at the time <span class="monospaced">isolate f</span> was called.  This leaks space, since, <em>semantically</em>, the
continuation returned by <span class="monospaced">isolate f</span> only needs the heap-allocated values reachable from <span class="monospaced">f</span> (and <span class="monospaced">base</span>).</p></div>
<div class="paragraph"><p>In practice, this probably isn&#8217;t a significant issue.  A common use of <span class="monospaced">isolate</span> is implement <span class="monospaced">abort</span>:</p></div>
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span></span><span class="k">fun</span><span class="w"> </span><span class="n">abort</span><span class="w"> </span><span class="n">th</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">throw</span><span class="w"> </span><span class="p">(</span><span class="n">isolate</span><span class="w"> </span><span class="n">th</span><span class="p">,</span><span class="w"> </span><span class="p">())</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>The continuation returned by <span class="monospaced">isolate th</span> is dead immediately after being thrown to&#8201;&#8212;&#8201;the continuation isn&#8217;t retained, so neither is the <em>semantic</em>
garbage it would have retained.</p></div>
<div class="paragraph"><p>But, it is easy enough to <em>move</em> onto the <em>empty</em> context <span class="monospaced">base</span> the capturing of the context that we want to be returned by <span class="monospaced">isolate f</span>:</p></div>
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span></span><span class="k">local</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">base</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">unit</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">unit</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="w">  </span><span class="n">callcc</span><span class="w"></span>
<span class="w">  </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">k1</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">   </span><span class="k">let</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="n">th</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">callcc</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">k2</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">throw</span><span class="w"> </span><span class="p">(</span><span class="n">k1</span><span class="p">,</span><span class="w"> </span><span class="n">k2</span><span class="p">))</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">(</span><span class="n">th</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">Exit</span><span class="p">.</span><span class="n">topLevelSuffix</span><span class="w"> </span><span class="p">())</span><span class="w"></span>
<span class="w">              </span><span class="k">handle</span><span class="w"> </span><span class="n">exn</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">MLtonExn</span><span class="p">.</span><span class="n">topLevelHandler</span><span class="w"> </span><span class="n">exn</span><span class="w"></span>
<span class="w">   </span><span class="k">in</span><span class="w"></span>
<span class="w">      </span><span class="k">raise</span><span class="w"> </span><span class="n">Fail</span><span class="w"> </span><span class="s">&quot;MLton.Cont.isolate: return from (wrapped) func&quot;</span><span class="w"></span>
<span class="w">   </span><span class="k">end</span><span class="p">)</span><span class="w"></span>
<span class="k">in</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">isolate</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="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="p">)</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">t</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">  </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">f</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">unit</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">  </span><span class="n">callcc</span><span class="w"></span>
<span class="w">  </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">k1</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">   </span><span class="n">throw</span><span class="w"> </span><span class="p">(</span><span class="n">base</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="w">          </span><span class="k">let</span><span class="w"></span>
<span class="w">             </span><span class="k">val</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">callcc</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">k2</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">throw</span><span class="w"> </span><span class="p">(</span><span class="n">k1</span><span class="p">,</span><span class="w"> </span><span class="n">k2</span><span class="p">))</span><span class="w"></span>
<span class="w">          </span><span class="k">in</span><span class="w"></span>
<span class="w">             </span><span class="n">throw</span><span class="w"> </span><span class="p">(</span><span class="n">base</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="n">f</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w"></span>
<span class="w">          </span><span class="k">end</span><span class="p">))</span><span class="w"></span>
<span class="k">end</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>This implementation now has the right space behavior; the continuation returned by <span class="monospaced">isolate f</span> will only retain the heap-allocated values reachable from <span class="monospaced">f</span> and from <span class="monospaced">base</span>.  (Technically, the continuation will retain two copies of the stack that was in place at the time <span class="monospaced">base</span> was evaluated, but we are assuming that that stack small.)</p></div>
<div class="paragraph"><p>One minor inefficiency of this implementation (given MLton&#8217;s implementation of continuations) is that every <span class="monospaced">callcc</span> and <span class="monospaced">throw</span> entails copying a stack (albeit, some of them are small).  We can avoid this in the evaluation of <span class="monospaced">base</span> by using a reference cell, because <span class="monospaced">base</span> is evaluated at the top-level:</p></div>
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span></span><span class="k">local</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">base</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">unit</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="p">)</span><span class="w"> </span><span class="n">option</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">  </span><span class="k">let</span><span class="w"></span>
<span class="w">     </span><span class="k">val</span><span class="w"> </span><span class="n">baseRef</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">unit</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="p">)</span><span class="w"> </span><span class="n">option</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="n">option</span><span class="w"> </span><span class="n">ref</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">ref</span><span class="w"> </span><span class="n">NONE</span><span class="w"></span>
<span class="w">     </span><span class="k">val</span><span class="w"> </span><span class="n">th</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">callcc</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">k</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">(</span><span class="n">base</span><span class="w"> </span><span class="n">:=</span><span class="w"> </span><span class="n">SOME</span><span class="w"> </span><span class="n">k</span><span class="p">;</span><span class="w"> </span><span class="n">NONE</span><span class="p">))</span><span class="w"></span>
<span class="w">  </span><span class="k">in</span><span class="w"></span>
<span class="w">     </span><span class="k">case</span><span class="w"> </span><span class="n">th</span><span class="w"> </span><span class="k">of</span><span class="w"></span>
<span class="w">        </span><span class="n">NONE</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">(</span><span class="k">case</span><span class="w"> </span><span class="n">!baseRef</span><span class="w"> </span><span class="k">of</span><span class="w"></span>
<span class="w">                    </span><span class="n">NONE</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="k">raise</span><span class="w"> </span><span class="n">Fail</span><span class="w"> </span><span class="s">&quot;MLton.Cont.isolate: missing base&quot;</span><span class="w"></span>
<span class="w">                  </span><span class="p">|</span><span class="w"> </span><span class="n">SOME</span><span class="w"> </span><span class="n">base</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">base</span><span class="p">)</span><span class="w"></span>
<span class="w">      </span><span class="p">|</span><span class="w"> </span><span class="n">SOME</span><span class="w"> </span><span class="n">th</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="k">let</span><span class="w"></span>
<span class="w">                      </span><span class="k">val</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">(</span><span class="n">th</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">Exit</span><span class="p">.</span><span class="n">topLevelSuffix</span><span class="w"> </span><span class="p">())</span><span class="w"></span>
<span class="w">                              </span><span class="k">handle</span><span class="w"> </span><span class="n">exn</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">MLtonExn</span><span class="p">.</span><span class="n">topLevelHandler</span><span class="w"> </span><span class="n">exn</span><span class="w"></span>
<span class="w">                   </span><span class="k">in</span><span class="w"></span>
<span class="w">                      </span><span class="k">raise</span><span class="w"> </span><span class="n">Fail</span><span class="w"> </span><span class="s">&quot;MLton.Cont.isolate: return from (wrapped)</span><span class="err"></span>
<span class="s">                      func&quot;</span><span class="w"></span>
<span class="w">                   </span><span class="k">end</span><span class="w"></span>
<span class="w">  </span><span class="k">end</span><span class="w"></span>
<span class="k">in</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">isolate</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="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="p">)</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">t</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">  </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">f</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">unit</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">  </span><span class="n">callcc</span><span class="w"></span>
<span class="w">  </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">k1</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">   </span><span class="n">throw</span><span class="w"> </span><span class="p">(</span><span class="n">base</span><span class="p">,</span><span class="w"> </span><span class="n">SOME</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">=&gt;</span><span class="w"></span>
<span class="w">          </span><span class="k">let</span><span class="w"></span>
<span class="w">             </span><span class="k">val</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">callcc</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">k2</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">throw</span><span class="w"> </span><span class="p">(</span><span class="n">k1</span><span class="p">,</span><span class="w"> </span><span class="n">k2</span><span class="p">))</span><span class="w"></span>
<span class="w">          </span><span class="k">in</span><span class="w"></span>
<span class="w">             </span><span class="n">throw</span><span class="w"> </span><span class="p">(</span><span class="n">base</span><span class="p">,</span><span class="w"> </span><span class="n">SOME</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">=&gt;</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="n">x</span><span class="p">))</span><span class="w"></span>
<span class="w">          </span><span class="k">end</span><span class="p">)))</span><span class="w"></span>
<span class="k">end</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>Now, to evaluate <span class="monospaced">base</span>, we only copy the stack once (instead of 3 times).  Because we don&#8217;t have a dummy continuation around to initialize the reference cell, the reference cell holds a continuation <span class="monospaced">option</span>.  To distinguish between the original evaluation of <span class="monospaced">base</span> (when we want to return the continuation) and the subsequent evaluations of <span class="monospaced">base</span> (when we want to evaluate a thunk), we capture a <span class="monospaced">(unit -&gt; unit) option</span> continuation.</p></div>
<div class="paragraph"><p>This seems to be as far as we can go without exploiting the concrete implementation of continuations in <a href="MLtonCont">MLtonCont</a>.  Examining the implementation, we note that the type of
continuations is given by</p></div>
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span></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="p">(</span><span class="n">unit</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">&#39;a</span><span class="p">)</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>and the implementation of <span class="monospaced">throw</span> is given by</p></div>
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span></span><span class="k">fun</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">throw&#39;</span><span class="w"> </span><span class="p">(</span><span class="n">k</span><span class="p">:</span><span class="w"> </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">v</span><span class="p">:</span><span class="w"> </span><span class="n">unit</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">&#39;a</span><span class="p">):</span><span class="w"> </span><span class="n">&#39;b</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">  </span><span class="p">(</span><span class="n">k</span><span class="w"> </span><span class="n">v</span><span class="p">;</span><span class="w"> </span><span class="k">raise</span><span class="w"> </span><span class="n">Fail</span><span class="w"> </span><span class="s">&quot;MLton.Cont.throw&#39;: return from continuation&quot;</span><span class="p">)</span><span class="w"></span>

<span class="k">fun</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">throw</span><span class="w"> </span><span class="p">(</span><span class="n">k</span><span class="p">:</span><span class="w"> </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">v</span><span class="p">:</span><span class="w"> </span><span class="n">&#39;a</span><span class="p">):</span><span class="w"> </span><span class="n">&#39;b</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">throw&#39;</span><span class="w"> </span><span class="p">(</span><span class="n">k</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="n">v</span><span class="p">)</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>Suffice to say, a continuation is simply a function that accepts a thunk to yield the thrown value and the body of the function performs the actual throw. Using this knowledge, we can create a dummy continuation to initialize <span class="monospaced">baseRef</span> and greatly simplify the body of <span class="monospaced">isolate</span>:</p></div>
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span></span><span class="k">local</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">base</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">unit</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="p">)</span><span class="w"> </span><span class="n">option</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">  </span><span class="k">let</span><span class="w"></span>
<span class="w">     </span><span class="k">val</span><span class="w"> </span><span class="n">baseRef</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">unit</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="p">)</span><span class="w"> </span><span class="n">option</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="n">ref</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">        </span><span class="n">ref</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">=&gt;</span><span class="w"> </span><span class="k">raise</span><span class="w"> </span><span class="n">Fail</span><span class="w"> </span><span class="s">&quot;MLton.Cont.isolate: missing base&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">     </span><span class="k">val</span><span class="w"> </span><span class="n">th</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">callcc</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">k</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">(</span><span class="n">baseRef</span><span class="w"> </span><span class="n">:=</span><span class="w"> </span><span class="n">k</span><span class="p">;</span><span class="w"> </span><span class="n">NONE</span><span class="p">))</span><span class="w"></span>
<span class="w">  </span><span class="k">in</span><span class="w"></span>
<span class="w">     </span><span class="k">case</span><span class="w"> </span><span class="n">th</span><span class="w"> </span><span class="k">of</span><span class="w"></span>
<span class="w">        </span><span class="n">NONE</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">!baseRef</span><span class="w"></span>
<span class="w">      </span><span class="p">|</span><span class="w"> </span><span class="n">SOME</span><span class="w"> </span><span class="n">th</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="k">let</span><span class="w"></span>
<span class="w">                      </span><span class="k">val</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">(</span><span class="n">th</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">Exit</span><span class="p">.</span><span class="n">topLevelSuffix</span><span class="w"> </span><span class="p">())</span><span class="w"></span>
<span class="w">                              </span><span class="k">handle</span><span class="w"> </span><span class="n">exn</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">MLtonExn</span><span class="p">.</span><span class="n">topLevelHandler</span><span class="w"> </span><span class="n">exn</span><span class="w"></span>
<span class="w">                   </span><span class="k">in</span><span class="w"></span>
<span class="w">                      </span><span class="k">raise</span><span class="w"> </span><span class="n">Fail</span><span class="w"> </span><span class="s">&quot;MLton.Cont.isolate: return from (wrapped)</span><span class="err"></span>
<span class="s">                      func&quot;</span><span class="w"></span>
<span class="w">                   </span><span class="k">end</span><span class="w"></span>
<span class="w">  </span><span class="k">end</span><span class="w"></span>
<span class="k">in</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">isolate</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="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="p">)</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">t</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">  </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">f</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">unit</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">  </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">v</span><span class="p">:</span><span class="w"> </span><span class="n">unit</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">&#39;a</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">  </span><span class="n">throw</span><span class="w"> </span><span class="p">(</span><span class="n">base</span><span class="p">,</span><span class="w"> </span><span class="n">SOME</span><span class="w"> </span><span class="p">(</span><span class="n">f</span><span class="w"> </span><span class="n">o</span><span class="w"> </span><span class="n">v</span><span class="p">))</span><span class="w"></span>
<span class="k">end</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>Note that this implementation of <span class="monospaced">isolate</span> makes it clear that the continuation returned by <span class="monospaced">isolate f</span> only retains the heap-allocated values reachable from <span class="monospaced">f</span> and <span class="monospaced">base</span>.  It also retains only one copy of the stack that was in place at the time <span class="monospaced">base</span> was evaluated.  Finally, it completely avoids making any copies of the stack that is in place at the time <span class="monospaced">isolate f</span> is evaluated; indeed, <span class="monospaced">isolate f</span> is a constant-time operation.</p></div>
<div class="paragraph"><p>Next, suppose we limited ourselves to capturing <span class="monospaced">unit</span> continuations with <span class="monospaced">callcc</span>.  We can&#8217;t pass the thunk to be evaluated in the <em>empty</em> context directly, but we can use a reference cell.</p></div>
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span></span><span class="k">local</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">thRef</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">unit</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="p">)</span><span class="w"> </span><span class="n">option</span><span class="w"> </span><span class="n">ref</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">ref</span><span class="w"> </span><span class="n">NONE</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">base</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><span class="p">=</span><span class="w"></span>
<span class="w">  </span><span class="k">let</span><span class="w"></span>
<span class="w">     </span><span class="k">val</span><span class="w"> </span><span class="n">baseRef</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><span class="n">ref</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">        </span><span class="n">ref</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">=&gt;</span><span class="w"> </span><span class="k">raise</span><span class="w"> </span><span class="n">Fail</span><span class="w"> </span><span class="s">&quot;MLton.Cont.isolate: missing base&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">     </span><span class="k">val</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">callcc</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">k</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">baseRef</span><span class="w"> </span><span class="n">:=</span><span class="w"> </span><span class="n">k</span><span class="p">)</span><span class="w"></span>
<span class="w">  </span><span class="k">in</span><span class="w"></span>
<span class="w">     </span><span class="k">case</span><span class="w"> </span><span class="n">!thRef</span><span class="w"> </span><span class="k">of</span><span class="w"></span>
<span class="w">        </span><span class="n">NONE</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">!baseRef</span><span class="w"></span>
<span class="w">      </span><span class="p">|</span><span class="w"> </span><span class="n">SOME</span><span class="w"> </span><span class="n">th</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">           </span><span class="k">let</span><span class="w"></span>
<span class="w">              </span><span class="k">val</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">thRef</span><span class="w"> </span><span class="n">:=</span><span class="w"> </span><span class="n">NONE</span><span class="w"></span>
<span class="w">              </span><span class="k">val</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">(</span><span class="n">th</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">Exit</span><span class="p">.</span><span class="n">topLevelSuffix</span><span class="w"> </span><span class="p">())</span><span class="w"></span>
<span class="w">                      </span><span class="k">handle</span><span class="w"> </span><span class="n">exn</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">MLtonExn</span><span class="p">.</span><span class="n">topLevelHandler</span><span class="w"> </span><span class="n">exn</span><span class="w"></span>
<span class="w">           </span><span class="k">in</span><span class="w"></span>
<span class="w">              </span><span class="k">raise</span><span class="w"> </span><span class="n">Fail</span><span class="w"> </span><span class="s">&quot;MLton.Cont.isolate: return from (wrapped) func&quot;</span><span class="w"></span>
<span class="w">           </span><span class="k">end</span><span class="w"></span>
<span class="w">  </span><span class="k">end</span><span class="w"></span>
<span class="k">in</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">isolate</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="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="p">)</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">t</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">  </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">f</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">unit</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">  </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">v</span><span class="p">:</span><span class="w"> </span><span class="n">unit</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">&#39;a</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">  </span><span class="k">let</span><span class="w"></span>
<span class="w">     </span><span class="k">val</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">thRef</span><span class="w"> </span><span class="n">:=</span><span class="w"> </span><span class="n">SOME</span><span class="w"> </span><span class="p">(</span><span class="n">f</span><span class="w"> </span><span class="n">o</span><span class="w"> </span><span class="n">v</span><span class="p">)</span><span class="w"></span>
<span class="w">  </span><span class="k">in</span><span class="w"></span>
<span class="w">     </span><span class="n">throw</span><span class="w"> </span><span class="p">(</span><span class="n">base</span><span class="p">,</span><span class="w"> </span><span class="p">())</span><span class="w"></span>
<span class="w">  </span><span class="k">end</span><span class="w"></span>
<span class="k">end</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>Note that it is important to set <span class="monospaced">thRef</span> to <span class="monospaced">NONE</span> before evaluating the thunk, so that the garbage collector doesn&#8217;t retain all the heap-allocated values reachable from <span class="monospaced">f</span> and <span class="monospaced">v</span> during the evaluation of <span class="monospaced">f (v ())</span>.  This is because <span class="monospaced">thRef</span> is still live during the evaluation of the thunk; in particular, it was allocated before the evaluation of <span class="monospaced">base</span> (and used after), and so is retained by continuation on which the thunk is evaluated.</p></div>
<div class="paragraph"><p>This implementation can be easily adapted to use MLton&#8217;s primitive stack copying operations.</p></div>
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span></span><span class="k">local</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">thRef</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">unit</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="p">)</span><span class="w"> </span><span class="n">option</span><span class="w"> </span><span class="n">ref</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">ref</span><span class="w"> </span><span class="n">NONE</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">base</span><span class="p">:</span><span class="w"> </span><span class="n">Thread</span><span class="p">.</span><span class="n">preThread</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">   </span><span class="k">let</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Thread</span><span class="p">.</span><span class="n">copyCurrent</span><span class="w"> </span><span class="p">()</span><span class="w"></span>
<span class="w">   </span><span class="k">in</span><span class="w"></span>
<span class="w">      </span><span class="k">case</span><span class="w"> </span><span class="n">!thRef</span><span class="w"> </span><span class="k">of</span><span class="w"></span>
<span class="w">         </span><span class="n">NONE</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">Thread</span><span class="p">.</span><span class="n">savedPre</span><span class="w"> </span><span class="p">()</span><span class="w"></span>
<span class="w">       </span><span class="p">|</span><span class="w"> </span><span class="n">SOME</span><span class="w"> </span><span class="n">th</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">            </span><span class="k">let</span><span class="w"></span>
<span class="w">               </span><span class="k">val</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">thRef</span><span class="w"> </span><span class="n">:=</span><span class="w"> </span><span class="n">NONE</span><span class="w"></span>
<span class="w">               </span><span class="k">val</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">(</span><span class="n">th</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">Exit</span><span class="p">.</span><span class="n">topLevelSuffix</span><span class="w"> </span><span class="p">())</span><span class="w"></span>
<span class="w">                       </span><span class="k">handle</span><span class="w"> </span><span class="n">exn</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">MLtonExn</span><span class="p">.</span><span class="n">topLevelHandler</span><span class="w"> </span><span class="n">exn</span><span class="w"></span>
<span class="w">            </span><span class="k">in</span><span class="w"></span>
<span class="w">               </span><span class="k">raise</span><span class="w"> </span><span class="n">Fail</span><span class="w"> </span><span class="s">&quot;MLton.Cont.isolate: return from (wrapped) func&quot;</span><span class="w"></span>
<span class="w">            </span><span class="k">end</span><span class="w"></span>
<span class="w">   </span><span class="k">end</span><span class="w"></span>
<span class="k">in</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">isolate</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="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="p">)</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">t</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">   </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">f</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">unit</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">   </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">v</span><span class="p">:</span><span class="w"> </span><span class="n">unit</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">&#39;a</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">   </span><span class="k">let</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">thRef</span><span class="w"> </span><span class="n">:=</span><span class="w"> </span><span class="n">SOME</span><span class="w"> </span><span class="p">(</span><span class="n">f</span><span class="w"> </span><span class="n">o</span><span class="w"> </span><span class="n">v</span><span class="p">)</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="n">new</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Thread</span><span class="p">.</span><span class="n">copy</span><span class="w"> </span><span class="n">base</span><span class="w"></span>
<span class="w">   </span><span class="k">in</span><span class="w"></span>
<span class="w">      </span><span class="n">Thread</span><span class="p">.</span><span class="n">switchTo</span><span class="w"> </span><span class="n">new</span><span class="w"></span>
<span class="w">   </span><span class="k">end</span><span class="w"></span>
<span class="k">end</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>In essence, <span class="monospaced">Thread.copyCurrent</span> copies the current execution stack and stores it in an implicit reference cell in the runtime system, which is fetchable with <span class="monospaced">Thread.savedPre</span>.  When we are ready to throw to the isolated function, <span class="monospaced">Thread.copy</span> copies the saved execution stack (because the stack is modified in place during execution, we need to retain a pristine copy in case the isolated function itself throws to other isolated functions) and <span class="monospaced">Thread.switchTo</span> abandons the current execution stack, installing the newly copied execution stack.</p></div>
<div class="paragraph"><p>The actual implementation of <span class="monospaced">MLton.Cont.isolate</span> simply adds some <span class="monospaced">Thread.atomicBegin</span> and <span class="monospaced">Thread.atomicEnd</span> commands, which effectively protect the global <span class="monospaced">thRef</span> and accommodate the fact that <span class="monospaced">Thread.switchTo</span> does an implicit <span class="monospaced">Thread.atomicEnd</span> (used for leaving a signal handler thread).</p></div>
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span></span><span class="k">local</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">thRef</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="n">unit</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="p">)</span><span class="w"> </span><span class="n">option</span><span class="w"> </span><span class="n">ref</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">ref</span><span class="w"> </span><span class="n">NONE</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">base</span><span class="p">:</span><span class="w"> </span><span class="n">Thread</span><span class="p">.</span><span class="n">preThread</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">   </span><span class="k">let</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Thread</span><span class="p">.</span><span class="n">copyCurrent</span><span class="w"> </span><span class="p">()</span><span class="w"></span>
<span class="w">   </span><span class="k">in</span><span class="w"></span>
<span class="w">      </span><span class="k">case</span><span class="w"> </span><span class="n">!thRef</span><span class="w"> </span><span class="k">of</span><span class="w"></span>
<span class="w">         </span><span class="n">NONE</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">Thread</span><span class="p">.</span><span class="n">savedPre</span><span class="w"> </span><span class="p">()</span><span class="w"></span>
<span class="w">       </span><span class="p">|</span><span class="w"> </span><span class="n">SOME</span><span class="w"> </span><span class="n">th</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">            </span><span class="k">let</span><span class="w"></span>
<span class="w">               </span><span class="k">val</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">thRef</span><span class="w"> </span><span class="n">:=</span><span class="w"> </span><span class="n">NONE</span><span class="w"></span>
<span class="w">               </span><span class="k">val</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">MLton</span><span class="p">.</span><span class="n">atomicEnd</span><span class="w"> </span><span class="cm">(* Match 1 *)</span><span class="w"></span>
<span class="w">               </span><span class="k">val</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">(</span><span class="n">th</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">Exit</span><span class="p">.</span><span class="n">topLevelSuffix</span><span class="w"> </span><span class="p">())</span><span class="w"></span>
<span class="w">                       </span><span class="k">handle</span><span class="w"> </span><span class="n">exn</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">MLtonExn</span><span class="p">.</span><span class="n">topLevelHandler</span><span class="w"> </span><span class="n">exn</span><span class="w"></span>
<span class="w">            </span><span class="k">in</span><span class="w"></span>
<span class="w">               </span><span class="k">raise</span><span class="w"> </span><span class="n">Fail</span><span class="w"> </span><span class="s">&quot;MLton.Cont.isolate: return from (wrapped) func&quot;</span><span class="w"></span>
<span class="w">            </span><span class="k">end</span><span class="w"></span>
<span class="w">   </span><span class="k">end</span><span class="w"></span>
<span class="k">in</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="n">isolate</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="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="p">)</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">t</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">   </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">f</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">unit</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">   </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">v</span><span class="p">:</span><span class="w"> </span><span class="n">unit</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">&#39;a</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">   </span><span class="k">let</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">MLton</span><span class="p">.</span><span class="n">atomicBegin</span><span class="w"> </span><span class="cm">(* Match 1 *)</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">thRef</span><span class="w"> </span><span class="n">:=</span><span class="w"> </span><span class="n">SOME</span><span class="w"> </span><span class="p">(</span><span class="n">f</span><span class="w"> </span><span class="n">o</span><span class="w"> </span><span class="n">v</span><span class="p">)</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="n">new</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Thread</span><span class="p">.</span><span class="n">copy</span><span class="w"> </span><span class="n">base</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="p">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">MLton</span><span class="p">.</span><span class="n">atomicBegin</span><span class="w"> </span><span class="cm">(* Match 2 *)</span><span class="w"></span>
<span class="w">   </span><span class="k">in</span><span class="w"></span>
<span class="w">      </span><span class="n">Thread</span><span class="p">.</span><span class="n">switchTo</span><span class="w"> </span><span class="n">new</span><span class="w"> </span><span class="cm">(* Match 2 *)</span><span class="w"></span>
<span class="w">   </span><span class="k">end</span><span class="w"></span>
<span class="k">end</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>It is perhaps interesting to note that the above implementation was originally <em>derived</em> by specializing implementations of the <a href="MLtonThread">MLtonThread</a> <span class="monospaced">new</span>, <span class="monospaced">prepare</span>, and <span class="monospaced">switch</span> functions as if their only use was in the following implementation of <span class="monospaced">isolate</span>:</p></div>
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span></span><span class="k">val</span><span class="w"> </span><span class="n">isolate</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="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="p">)</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">t</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">   </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">f</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">unit</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">   </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">v</span><span class="p">:</span><span class="w"> </span><span class="n">unit</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">&#39;a</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">   </span><span class="k">let</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="n">th</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">(</span><span class="n">f</span><span class="w"> </span><span class="p">(</span><span class="n">v</span><span class="w"> </span><span class="p">())</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">Exit</span><span class="p">.</span><span class="n">topLevelSuffix</span><span class="w"> </span><span class="p">())</span><span class="w"></span>
<span class="w">               </span><span class="k">handle</span><span class="w"> </span><span class="n">exn</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">MLtonExn</span><span class="p">.</span><span class="n">topLevelHandler</span><span class="w"> </span><span class="n">exn</span><span class="w"></span>
<span class="w">      </span><span class="k">val</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">MLton</span><span class="p">.</span><span class="n">Thread</span><span class="p">.</span><span class="n">prepare</span><span class="w"> </span><span class="p">(</span><span class="n">MLton</span><span class="p">.</span><span class="n">Thread</span><span class="p">.</span><span class="n">new</span><span class="w"> </span><span class="n">th</span><span class="p">,</span><span class="w"> </span><span class="p">())</span><span class="w"></span>
<span class="w">   </span><span class="k">in</span><span class="w"></span>
<span class="w">      </span><span class="n">MLton</span><span class="p">.</span><span class="n">Thread</span><span class="p">.</span><span class="n">switch</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">=&gt;</span><span class="w"> </span><span class="n">t</span><span class="p">)</span><span class="w"></span>
<span class="w">   </span><span class="k">end</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>It was pleasant to discover that it could equally well be <em>derived</em> starting from the <span class="monospaced">callcc</span> and <span class="monospaced">throw</span> implementation.</p></div>
<div class="paragraph"><p>As a final comment, we noted that the degree to which the context of <span class="monospaced">base</span> could be considered <em>empty</em> (i.e., retaining few heap-allocated values) depended upon a slightly MLton-esque view.  In particular, MLton does not heap allocate executable code.  So, although the <span class="monospaced">base</span> context keeps a lot of unevaluated code <em>live</em>, such code is not heap allocated.  In a system like SML/NJ, that does heap allocate executable code, one might want it to be the case that after throwing to an isolated function, the garbage collector retains only the code necessary to evaluate the function, and not any code that was necessary to evaluate the <span class="monospaced">base</span> context.</p></div>
</div>
</div>
</div>
<div id="footnotes"><hr></div>
<div id="footer">
<div id="footer-text">
</div>
<div id="footer-badges">
</div>
</div>
</body>
</html>
