<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>blog.ielliott.io</title>
    <link href="https://blog.ielliott.io/feed.xml" rel="self" type="application/atom+xml" />
    <link href="https://blog.ielliott.io/" rel="alternate" type="text/html" />
    <id>https://blog.ielliott.io/feed.xml</id>
    <author>
        <name>Isaac Elliott</name>
        
        <email>blog@id.ielliott.io</email>
        
    </author>
    <updated>2026-03-30T00:30:00Z</updated>
    <entry>
    <title>Local Hoogle</title>
    <link href="https://blog.ielliott.io/local-hoogle" />
    
    <id>https://blog.ielliott.io/local-hoogle</id>
    
    <published>2026-03-30T00:30:00Z</published>
    <updated>2026-03-30T00:30:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/local-hoogle"><![CDATA[<p><a href="https://github.com/ndmitchell/hoogle">Hoogle</a> didn’t work when I tried to use it for local documentation search,
so I fixed it.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/local-hoogle"><![CDATA[
      
      <div id="toc">
<h3>Contents</h3>
<ul>
<li><a href="#hoogle-patches">Hoogle patches</a>
<ul>
<li><a href="#proof-of-concept-read-haddock-html-field-from-ghc-pkg-entries">Proof of concept: read <code>haddock-html</code> field from <code>ghc-pkg</code> entries</a></li>
<li><a href="#proof-of-concept-make-generate---local-respect-ghc_environment-variable">Proof of concept: make <code>generate --local</code> respect <code>GHC_ENVIRONMENT</code> variable</a></li>
</ul></li>
<li><a href="#cabal-patch">Cabal patch</a></li>
<li><a href="#usage">Usage</a></li>
</ul>
</div>
<p><a href="https://github.com/ndmitchell/hoogle">Hoogle</a> didn’t work when I tried to use it for local documentation search,
so I fixed it.</p>
<h2 id="hoogle-patches"><a href="#hoogle-patches">Hoogle patches</a></h2>
<p>See also: my fork <a href="https://github.com/LightAndLight/hoogle">here</a>.</p>
<h3 id="proof-of-concept-read-haddock-html-field-from-ghc-pkg-entries"><a href="#proof-of-concept-read-haddock-html-field-from-ghc-pkg-entries">Proof of concept: read <code>haddock-html</code> field from <code>ghc-pkg</code> entries</a></h3>
<p>When I tried to generate a Hoogle database (on NixOS) I got this error:</p>
<pre><code>$ cabal exec -- hoogle generate --local --database db.hoo
Starting generate
Reading ghc-pkg... 0.04s

Packages missing documentation: array base binary bytestring Cabal Cabal-syntax containers deepseq directory exceptions filepath ghc ghc-bignum ghc-boot ghc-boot-th ghc-compact ghc-experimental ghc-heap ghc-internal ghc-platform ghc-prim ghc-toolchain ghci haskeline hpc integer-gmp mtl os-string parsec pretty process rts semaphore-compat stm system-cxx-std-lib template-haskell terminfo text time transformers unix xhtml
No packages were found, aborting (use no arguments to index all of Stackage)</code></pre>
<p>Hoogle was using hard-coded package documentation locations that weren’t present on my system.
<a href="https://downloads.haskell.org/ghc/latest/docs/users_guide/packages.html#package-management-the-ghc-pkg-command"><code>ghc-pkg</code></a>
package descriptions have a <code>haddock-html</code> field, so Hoogle should just use that.</p>
<details open>
<summary>
Hoogle patch 1/2
</summary>
<div class="sourceCode" id="cb2"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">diff --git a/src/Input/Cabal.hs b/src/Input/Cabal.hs</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>index 6180fe06..f31292ec 100644</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="dt">--- a/src/Input/Cabal.hs</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="dt">+++ b/src/Input/Cabal.hs</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="dt">@@ -117,8 +117,32 @@ readGhcPkg settings = do</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>     let fixer p = p{packageLibrary = True, packageDocs = g &lt;$&gt; packageDocs p}</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>     let f ((stripPrefix &quot;name: &quot; -&gt; Just x):xs) = Just (mkPackageName $ trimStart x, fixer $ readCabal settings $ bstrPack $ unlines xs)</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>         f _ = Nothing</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="st">-    pure $ Map.fromList $ mapMaybe f $ splitOn [&quot;---&quot;] $ lines $ filter (/= &#39;\r&#39;) $ UTF8.toString stdout</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="st">-</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="va">+    let</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a><span class="va">+        withHaddockHtml (name, package) =</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a><span class="va">+            case packageDocs package of</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a><span class="va">+                Nothing -&gt; do</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a><span class="va">+                    packageDocs&#39; &lt;- readGhcPkgHaddockHtml (unPackageName name)</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a><span class="va">+                    pure (name, package{packageDocs = packageDocs&#39;})</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a><span class="va">+                Just{} -&gt;</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a><span class="va">+                    pure (name, package)</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a><span class="va">+    fmap Map.fromList $ traverse withHaddockHtml $ mapMaybe f $ splitOn [&quot;---&quot;] $ lines $ filter (/= &#39;\r&#39;) $ UTF8.toString stdout</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a><span class="va">+</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a><span class="va">+readGhcPkgHaddockHtml ::</span></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a><span class="va">+    -- | Package name</span></span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a><span class="va">+    String -&gt;</span></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a><span class="va">+    IO (Maybe FilePath)</span></span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a><span class="va">+readGhcPkgHaddockHtml packageName = do</span></span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a><span class="va">+    let args = [&quot;field&quot;, packageName, &quot;haddock-html&quot;, &quot;--expand-pkgroot&quot;, &quot;--simple&quot;]</span></span>
<span id="cb2-27"><a href="#cb2-27" aria-hidden="true" tabindex="-1"></a><span class="va">+    (exit, stdout, stderr) &lt;- BS.readProcessWithExitCode &quot;ghc-pkg&quot; args mempty</span></span>
<span id="cb2-28"><a href="#cb2-28" aria-hidden="true" tabindex="-1"></a><span class="va">+    if exit /= ExitSuccess</span></span>
<span id="cb2-29"><a href="#cb2-29" aria-hidden="true" tabindex="-1"></a><span class="va">+        then do</span></span>
<span id="cb2-30"><a href="#cb2-30" aria-hidden="true" tabindex="-1"></a><span class="va">+            putStrLn &quot;error when calling ghc-pkg:&quot;</span></span>
<span id="cb2-31"><a href="#cb2-31" aria-hidden="true" tabindex="-1"></a><span class="va">+            putStrLn $ &quot;args: &quot; ++ show args</span></span>
<span id="cb2-32"><a href="#cb2-32" aria-hidden="true" tabindex="-1"></a><span class="va">+            putStrLn $ &quot;exit: &quot; ++ show exit</span></span>
<span id="cb2-33"><a href="#cb2-33" aria-hidden="true" tabindex="-1"></a><span class="va">+            putStrLn $ &quot;stderr: &quot; ++ UTF8.toString stderr</span></span>
<span id="cb2-34"><a href="#cb2-34" aria-hidden="true" tabindex="-1"></a><span class="va">+            pure Nothing</span></span>
<span id="cb2-35"><a href="#cb2-35" aria-hidden="true" tabindex="-1"></a><span class="va">+        else</span></span>
<span id="cb2-36"><a href="#cb2-36" aria-hidden="true" tabindex="-1"></a><span class="va">+            pure . Just . trimEnd $ UTF8.toString stdout</span></span>
<span id="cb2-37"><a href="#cb2-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-38"><a href="#cb2-38" aria-hidden="true" tabindex="-1"></a> -- | Given a tarball of Cabal files, parse the latest version of each package.</span>
<span id="cb2-39"><a href="#cb2-39" aria-hidden="true" tabindex="-1"></a> parseCabalTarball :: Settings -&gt; FilePath -&gt; IO (Map.Map PkgName Package)</span></code></pre></div>
</details>
<h3 id="proof-of-concept-make-generate---local-respect-ghc_environment-variable"><a href="#proof-of-concept-make-generate---local-respect-ghc_environment-variable">Proof of concept: make <code>generate --local</code> respect <code>GHC_ENVIRONMENT</code> variable</a></h3>
<p>Now Hoogle doesn’t crash on my system:</p>
<pre><code>$ cabal exec -- hoogle generate --local --database db.hoo
Starting generate
Reading ghc-pkg... 1.04s
[6/42] bytestring... 0.06s
[12/42] ghc... 2.10s
[19/42] ghc-prim... 0.26s
[37/42] xhtml... 0.02s
Packages missing documentation: ghc-compact ghc-experimental integer-gmp rts system-cxx-std-lib
Found 30 warnings when processing items

Reordering items... 0.03s
Writing tags... 0.10s
Writing names... 0.10s
Writing types... 0.37s
Took 6.76s</code></pre>
<p>But it only includes GHC’s boot libraries in the generated index; my project’s dependencies are missing.
I made Hoogle use the
<a href="https://downloads.haskell.org/ghc/latest/docs/users_guide/packages.html#envvar-GHC_ENVIRONMENT"><code>GHC_ENVIRONMENT</code></a>
variable to decide which packages should be included in the generated database
(this variable is provided by <code>cabal exec</code>).
I also needed this part of Hoogle to use package IDs instead of package names.</p>
<p>This code does the job, but it feels hacky.
I wouldn’t want it to be merged into Hoogle as-is.</p>
<details open>
<summary>
Hoogle patch 2/2
</summary>
<div class="sourceCode" id="cb4"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">diff --git a/src/Input/Cabal.hs b/src/Input/Cabal.hs</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>index f31292ec..31aee29d 100644</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="dt">--- a/src/Input/Cabal.hs</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="dt">+++ b/src/Input/Cabal.hs</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="dt">@@ -21,6 +21,7 @@ import System.Exit</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a> import qualified System.Process.ByteString as BS</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a> import qualified Data.ByteString.UTF8 as UTF8</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a> import System.Directory</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="va">+import System.Environment</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a> import Data.Maybe</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a> import Data.Tuple.Extra</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a> import qualified Data.Map.Strict as Map</span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="dt">@@ -86,9 +87,29 @@ packagePopularity cbl = mp `seq` (errs, mp)</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a> ---------------------------------------------------------------------</span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a> -- READERS</span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a><span class="va">+-- | Returns a list of extra ghc-pkg flags, and an optional list of enabled packages.</span></span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a><span class="va">+readGhcEnvironment :: IO ([String], Maybe [String])</span></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a><span class="va">+readGhcEnvironment = do</span></span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a><span class="va">+    mFile &lt;- lookupEnv &quot;GHC_ENVIRONMENT&quot;</span></span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a><span class="va">+    case mFile of</span></span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a><span class="va">+        Nothing -&gt; pure ([], Nothing)</span></span>
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a><span class="va">+        Just file -&gt; do</span></span>
<span id="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a><span class="va">+            contents &lt;- readFile file</span></span>
<span id="cb4-25"><a href="#cb4-25" aria-hidden="true" tabindex="-1"></a><span class="va">+            let</span></span>
<span id="cb4-26"><a href="#cb4-26" aria-hidden="true" tabindex="-1"></a><span class="va">+                f line rest@(flags, enabledPackages)</span></span>
<span id="cb4-27"><a href="#cb4-27" aria-hidden="true" tabindex="-1"></a><span class="va">+                    | line == &quot;clear-package-db&quot; = (&quot;--no-user-package-db&quot; : flags, enabledPackages)</span></span>
<span id="cb4-28"><a href="#cb4-28" aria-hidden="true" tabindex="-1"></a><span class="va">+                    | line == &quot;global-package-db&quot; = (&quot;--global&quot; : flags, enabledPackages)</span></span>
<span id="cb4-29"><a href="#cb4-29" aria-hidden="true" tabindex="-1"></a><span class="va">+                    | Just packageDb &lt;- stripPrefix &quot;package-db &quot; line = ((&quot;--package-db=&quot; ++ packageDb) : flags, enabledPackages)</span></span>
<span id="cb4-30"><a href="#cb4-30" aria-hidden="true" tabindex="-1"></a><span class="va">+                    | Just name &lt;- stripPrefix &quot;package-id &quot; line = (flags, name : enabledPackages)</span></span>
<span id="cb4-31"><a href="#cb4-31" aria-hidden="true" tabindex="-1"></a><span class="va">+                    | otherwise = rest</span></span>
<span id="cb4-32"><a href="#cb4-32" aria-hidden="true" tabindex="-1"></a><span class="va">+</span></span>
<span id="cb4-33"><a href="#cb4-33" aria-hidden="true" tabindex="-1"></a><span class="va">+            let (flags, enabledPackages) = foldr f ([], []) (lines contents)</span></span>
<span id="cb4-34"><a href="#cb4-34" aria-hidden="true" tabindex="-1"></a><span class="va">+            pure (flags, Just enabledPackages)</span></span>
<span id="cb4-35"><a href="#cb4-35" aria-hidden="true" tabindex="-1"></a><span class="va">+</span></span>
<span id="cb4-36"><a href="#cb4-36" aria-hidden="true" tabindex="-1"></a> -- | Run &#39;ghc-pkg&#39; and get a list of packages which are installed.</span>
<span id="cb4-37"><a href="#cb4-37" aria-hidden="true" tabindex="-1"></a> readGhcPkg :: Settings -&gt; IO (Map.Map PkgName Package)</span>
<span id="cb4-38"><a href="#cb4-38" aria-hidden="true" tabindex="-1"></a> readGhcPkg settings = do</span>
<span id="cb4-39"><a href="#cb4-39" aria-hidden="true" tabindex="-1"></a><span class="va">+    (ghcPkgFlags, mEnabledPackages) &lt;- readGhcEnvironment</span></span>
<span id="cb4-40"><a href="#cb4-40" aria-hidden="true" tabindex="-1"></a>     topdir &lt;- findExecutable &quot;ghc-pkg&quot;</span>
<span id="cb4-41"><a href="#cb4-41" aria-hidden="true" tabindex="-1"></a>     (exit, stdout, stderr) &lt;-</span>
<span id="cb4-42"><a href="#cb4-42" aria-hidden="true" tabindex="-1"></a>     -- From GHC 9.0.1, the `haddock-html` field in `*.conf` files for GHC boot</span>
<span id="cb4-43"><a href="#cb4-43" aria-hidden="true" tabindex="-1"></a><span class="dt">@@ -108,31 +129,57 @@ readGhcPkg settings = do</span></span>
<span id="cb4-44"><a href="#cb4-44" aria-hidden="true" tabindex="-1"></a>     -- correct manually the affected `*.conf` files.</span>
<span id="cb4-45"><a href="#cb4-45" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-46"><a href="#cb4-46" aria-hidden="true" tabindex="-1"></a>     -- important to use BS process reading so it&#39;s in Binary format, see #194</span>
<span id="cb4-47"><a href="#cb4-47" aria-hidden="true" tabindex="-1"></a><span class="st">-      BS.readProcessWithExitCode &quot;ghc-pkg&quot; [&quot;dump&quot;, &quot;--expand-pkgroot&quot;] mempty</span></span>
<span id="cb4-48"><a href="#cb4-48" aria-hidden="true" tabindex="-1"></a><span class="va">+      BS.readProcessWithExitCode &quot;ghc-pkg&quot; ([&quot;dump&quot;, &quot;--expand-pkgroot&quot;] ++ ghcPkgFlags) mempty</span></span>
<span id="cb4-49"><a href="#cb4-49" aria-hidden="true" tabindex="-1"></a>     when (exit /= ExitSuccess) $</span>
<span id="cb4-50"><a href="#cb4-50" aria-hidden="true" tabindex="-1"></a>         errorIO $ &quot;Error when reading from ghc-pkg, &quot; ++ show exit ++ &quot;\n&quot; ++ UTF8.toString stderr</span>
<span id="cb4-51"><a href="#cb4-51" aria-hidden="true" tabindex="-1"></a>     let g (stripPrefix &quot;$topdir&quot; -&gt; Just x) | Just t &lt;- topdir = takeDirectory t ++ x</span>
<span id="cb4-52"><a href="#cb4-52" aria-hidden="true" tabindex="-1"></a>         -- ^ Backwards compatibility with GHC &lt; 9.0</span>
<span id="cb4-53"><a href="#cb4-53" aria-hidden="true" tabindex="-1"></a>         g x = x</span>
<span id="cb4-54"><a href="#cb4-54" aria-hidden="true" tabindex="-1"></a>     let fixer p = p{packageLibrary = True, packageDocs = g &lt;$&gt; packageDocs p}</span>
<span id="cb4-55"><a href="#cb4-55" aria-hidden="true" tabindex="-1"></a><span class="st">-    let f ((stripPrefix &quot;name: &quot; -&gt; Just x):xs) = Just (mkPackageName $ trimStart x, fixer $ readCabal settings $ bstrPack $ unlines xs)</span></span>
<span id="cb4-56"><a href="#cb4-56" aria-hidden="true" tabindex="-1"></a><span class="va">+</span></span>
<span id="cb4-57"><a href="#cb4-57" aria-hidden="true" tabindex="-1"></a><span class="va">+    let</span></span>
<span id="cb4-58"><a href="#cb4-58" aria-hidden="true" tabindex="-1"></a><span class="va">+        findPackageId [] = Nothing</span></span>
<span id="cb4-59"><a href="#cb4-59" aria-hidden="true" tabindex="-1"></a><span class="va">+        findPackageId (x:xs)</span></span>
<span id="cb4-60"><a href="#cb4-60" aria-hidden="true" tabindex="-1"></a><span class="va">+            | Just rest &lt;- stripPrefix &quot;id:&quot; x =</span></span>
<span id="cb4-61"><a href="#cb4-61" aria-hidden="true" tabindex="-1"></a><span class="va">+                if null rest</span></span>
<span id="cb4-62"><a href="#cb4-62" aria-hidden="true" tabindex="-1"></a><span class="va">+                    then</span></span>
<span id="cb4-63"><a href="#cb4-63" aria-hidden="true" tabindex="-1"></a><span class="va">+                        -- some package database entries have the `id` field&#39;s value</span></span>
<span id="cb4-64"><a href="#cb4-64" aria-hidden="true" tabindex="-1"></a><span class="va">+                        -- on the next line.</span></span>
<span id="cb4-65"><a href="#cb4-65" aria-hidden="true" tabindex="-1"></a><span class="va">+                        --</span></span>
<span id="cb4-66"><a href="#cb4-66" aria-hidden="true" tabindex="-1"></a><span class="va">+                        -- should really use a proper parser.</span></span>
<span id="cb4-67"><a href="#cb4-67" aria-hidden="true" tabindex="-1"></a><span class="va">+                        case xs of</span></span>
<span id="cb4-68"><a href="#cb4-68" aria-hidden="true" tabindex="-1"></a><span class="va">+                            x&#39;:_xs&#39; -&gt; Just $ trimStart x&#39;</span></span>
<span id="cb4-69"><a href="#cb4-69" aria-hidden="true" tabindex="-1"></a><span class="va">+                            [] -&gt; Nothing</span></span>
<span id="cb4-70"><a href="#cb4-70" aria-hidden="true" tabindex="-1"></a><span class="va">+                    else Just $ trimStart rest</span></span>
<span id="cb4-71"><a href="#cb4-71" aria-hidden="true" tabindex="-1"></a><span class="va">+            | otherwise = findPackageId xs</span></span>
<span id="cb4-72"><a href="#cb4-72" aria-hidden="true" tabindex="-1"></a><span class="va">+</span></span>
<span id="cb4-73"><a href="#cb4-73" aria-hidden="true" tabindex="-1"></a><span class="va">+    let</span></span>
<span id="cb4-74"><a href="#cb4-74" aria-hidden="true" tabindex="-1"></a><span class="va">+        f ((stripPrefix &quot;name: &quot; -&gt; Just x):xs)</span></span>
<span id="cb4-75"><a href="#cb4-75" aria-hidden="true" tabindex="-1"></a><span class="va">+            | Just pId &lt;- findPackageId xs</span></span>
<span id="cb4-76"><a href="#cb4-76" aria-hidden="true" tabindex="-1"></a><span class="va">+            , maybe True (pId `elem`) mEnabledPackages =</span></span>
<span id="cb4-77"><a href="#cb4-77" aria-hidden="true" tabindex="-1"></a><span class="va">+            Just (pId, mkPackageName $ trimStart x, fixer $ readCabal settings $ bstrPack $ unlines xs)</span></span>
<span id="cb4-78"><a href="#cb4-78" aria-hidden="true" tabindex="-1"></a>         f _ = Nothing</span>
<span id="cb4-79"><a href="#cb4-79" aria-hidden="true" tabindex="-1"></a><span class="va">+</span></span>
<span id="cb4-80"><a href="#cb4-80" aria-hidden="true" tabindex="-1"></a>     let</span>
<span id="cb4-81"><a href="#cb4-81" aria-hidden="true" tabindex="-1"></a><span class="st">-        withHaddockHtml (name, package) =</span></span>
<span id="cb4-82"><a href="#cb4-82" aria-hidden="true" tabindex="-1"></a><span class="va">+        withHaddockHtml (pId, name, package) =</span></span>
<span id="cb4-83"><a href="#cb4-83" aria-hidden="true" tabindex="-1"></a>             case packageDocs package of</span>
<span id="cb4-84"><a href="#cb4-84" aria-hidden="true" tabindex="-1"></a>                 Nothing -&gt; do</span>
<span id="cb4-85"><a href="#cb4-85" aria-hidden="true" tabindex="-1"></a><span class="st">-                    packageDocs&#39; &lt;- readGhcPkgHaddockHtml (unPackageName name)</span></span>
<span id="cb4-86"><a href="#cb4-86" aria-hidden="true" tabindex="-1"></a><span class="st">-                    pure (name, package{packageDocs = packageDocs&#39;})</span></span>
<span id="cb4-87"><a href="#cb4-87" aria-hidden="true" tabindex="-1"></a><span class="va">+                    packageDocs&#39; &lt;- readGhcPkgHaddockHtml ghcPkgFlags pId</span></span>
<span id="cb4-88"><a href="#cb4-88" aria-hidden="true" tabindex="-1"></a><span class="va">+                    pure (pId, name, package{packageDocs = packageDocs&#39;})</span></span>
<span id="cb4-89"><a href="#cb4-89" aria-hidden="true" tabindex="-1"></a>                 Just{} -&gt;</span>
<span id="cb4-90"><a href="#cb4-90" aria-hidden="true" tabindex="-1"></a><span class="st">-                    pure (name, package)</span></span>
<span id="cb4-91"><a href="#cb4-91" aria-hidden="true" tabindex="-1"></a><span class="st">-    fmap Map.fromList $ traverse withHaddockHtml $ mapMaybe f $ splitOn [&quot;---&quot;] $ lines $ filter (/= &#39;\r&#39;) $ UTF8.toString stdout</span></span>
<span id="cb4-92"><a href="#cb4-92" aria-hidden="true" tabindex="-1"></a><span class="va">+                    pure (pId, name, package)</span></span>
<span id="cb4-93"><a href="#cb4-93" aria-hidden="true" tabindex="-1"></a><span class="va">+    </span></span>
<span id="cb4-94"><a href="#cb4-94" aria-hidden="true" tabindex="-1"></a><span class="va">+    let dump = splitOn [&quot;---&quot;] $ lines $ filter (/= &#39;\r&#39;) $ UTF8.toString stdout</span></span>
<span id="cb4-95"><a href="#cb4-95" aria-hidden="true" tabindex="-1"></a><span class="va">+    Map.fromList . fmap (\(_pId, name, pkg) -&gt; (name, pkg)) &lt;$&gt; traverse withHaddockHtml (mapMaybe f dump)</span></span>
<span id="cb4-96"><a href="#cb4-96" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-97"><a href="#cb4-97" aria-hidden="true" tabindex="-1"></a> readGhcPkgHaddockHtml ::</span>
<span id="cb4-98"><a href="#cb4-98" aria-hidden="true" tabindex="-1"></a><span class="st">-    -- | Package name</span></span>
<span id="cb4-99"><a href="#cb4-99" aria-hidden="true" tabindex="-1"></a><span class="va">+    -- | Extra ghc-pkg flags</span></span>
<span id="cb4-100"><a href="#cb4-100" aria-hidden="true" tabindex="-1"></a><span class="va">+    [String] -&gt;</span></span>
<span id="cb4-101"><a href="#cb4-101" aria-hidden="true" tabindex="-1"></a><span class="va">+    -- | Package ID</span></span>
<span id="cb4-102"><a href="#cb4-102" aria-hidden="true" tabindex="-1"></a>     String -&gt;</span>
<span id="cb4-103"><a href="#cb4-103" aria-hidden="true" tabindex="-1"></a>     IO (Maybe FilePath)</span>
<span id="cb4-104"><a href="#cb4-104" aria-hidden="true" tabindex="-1"></a><span class="st">-readGhcPkgHaddockHtml packageName = do</span></span>
<span id="cb4-105"><a href="#cb4-105" aria-hidden="true" tabindex="-1"></a><span class="st">-    let args = [&quot;field&quot;, packageName, &quot;haddock-html&quot;, &quot;--expand-pkgroot&quot;, &quot;--simple&quot;]</span></span>
<span id="cb4-106"><a href="#cb4-106" aria-hidden="true" tabindex="-1"></a><span class="va">+readGhcPkgHaddockHtml flags pkgId = do</span></span>
<span id="cb4-107"><a href="#cb4-107" aria-hidden="true" tabindex="-1"></a><span class="va">+    let args = [&quot;field&quot;, pkgId, &quot;haddock-html&quot;, &quot;--unit-id&quot;, &quot;--expand-pkgroot&quot;, &quot;--simple&quot;] ++ flags</span></span>
<span id="cb4-108"><a href="#cb4-108" aria-hidden="true" tabindex="-1"></a>     (exit, stdout, stderr) &lt;- BS.readProcessWithExitCode &quot;ghc-pkg&quot; args mempty</span>
<span id="cb4-109"><a href="#cb4-109" aria-hidden="true" tabindex="-1"></a>     if exit /= ExitSuccess</span>
<span id="cb4-110"><a href="#cb4-110" aria-hidden="true" tabindex="-1"></a>         then do</span></code></pre></div>
</details>
<h2 id="cabal-patch"><a href="#cabal-patch">Cabal patch</a></h2>
<p>Fixes a <a href="https://github.com/haskell/cabal/issues/11217">Cabal bug</a> that caused Haddock to sometimes generate invalid URLs.
In Cabal’s main branch as <a href="https://github.com/haskell/cabal/commit/423ce6c8032cb66a78c8068533c295b99416841c">this commit</a>.</p>
<details open>
<summary>
<code>Cabal/src/Distribution/Simple/Program/HcPkg.hs</code>
</summary>
<div class="sourceCode" id="cb5"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">diff --git a/Cabal/src/Distribution/Simple/Program/HcPkg.hs b/Cabal/src/Distribution/Simple/Program/HcPkg.hs</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>index a494bc63f..7ad7eba4e 100644</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="dt">--- a/Cabal/src/Distribution/Simple/Program/HcPkg.hs</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="dt">+++ b/Cabal/src/Distribution/Simple/Program/HcPkg.hs</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="dt">@@ -351,7 +351,7 @@ mungePackagePaths pkgroot pkginfo =</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>     , libraryDynDirs = mungePaths (libraryDynDirs pkginfo)</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>     , frameworkDirs = mungePaths (frameworkDirs pkginfo)</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>     , haddockInterfaces = mungePaths (haddockInterfaces pkginfo)</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="st">-    , haddockHTMLs = mungeUrls (haddockHTMLs pkginfo)</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="va">+    , haddockHTMLs = mungePaths (mungeUrls (haddockHTMLs pkginfo))</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>     }</span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>   where</span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>     mungePaths = map mungePath</span></code></pre></div>
</details>
<h2 id="usage"><a href="#usage">Usage</a></h2>
<p>With the patched versions of Cabal and Hoogle, I can build a local Hoogle database for a Haskell project and its dependencies.</p>
<p>To my <code>cabal.project</code> file, I add:</p>
<pre><code>documentation: True
haddock-hoogle: True
haddock-html: True

package *
  documentation: True
  haddock-hoogle: True
  haddock-html: True</code></pre>
<p>The first block configures docs / Hoogle for the project’s packages, and the second block is for the project’s dependencies.
If you don’t care about searching your project’s code then omit the first block.</p>
<p>Then I run:</p>
<pre><code>$ cabal build all
$ cabal exec -- hoogle generate --local --database db.hoo
$ hoogle serve --local --database db.hoo</code></pre>
    ]]></content>
    
</entry>
<entry>
    <title>Finishing BioShock</title>
    <link href="https://blog.ielliott.io/finishing-bioshock" />
    
    <id>https://blog.ielliott.io/finishing-bioshock</id>
    
    <published>2026-03-28T00:45:00Z</published>
    <updated>2026-03-28T00:45:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/finishing-bioshock"><![CDATA[<p>In October 2025 I finished playing BioShock. It only took two years.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/finishing-bioshock"><![CDATA[
      
      <p>In October 2025 I finished playing BioShock. It only took two years.</p>
<p><img src="./images/2025-10-26-bioshock-screenshot.png" alt="A screenshot from the game"></p>
<div id="toc">
<h3>Contents</h3>
<ul>
<li><a href="#looking-glass-studios-approach-to-game-design">Looking Glass Studios’ approach to game design</a></li>
<li><a href="#tangent-old-websites">Tangent: old websites!</a></li>
<li><a href="#why-i-took-so-long-to-finish-bioshock">Why I took so long to finish BioShock</a></li>
</ul>
</div>
<p>One reason I’m interested in BioShock is its pedigree in the gaming industry.
BioShock, released in 2007, was co-developed by <a href="https://en.wikipedia.org/wiki/Irrational_Games">Irrational Games / 2K Boston</a> and <a href="https://en.wikipedia.org/wiki/2K_Australia">Irrational Games Australia / 2K Australia</a>.
As an Australian, I was excited to learn about Australian involvement in such a famous game.
When it was shut down in 2015, 2K Australia was <a href="https://web.archive.org/web/20180219031310/https://www.kotaku.com.au/2015/04/the-heartwarming-response-to-the-closure-of-2k-australia/">the last AAA studio in Australia</a>.</p>
<details class="aside" open>
<summary>
Aside
</summary>
2K Australia was also the primary developer of the somewhat entertaining <a href="https://en.wikipedia.org/wiki/Borderlands:_The_Pre-Sequel">Borderlands: The Pre-Sequel</a>, a Borderlands (❤) spin-off set on <a href="https://borderlands.fandom.com/wiki/Pandora">Pandora</a>’s moon, which is apparently inhabited by Australians.
</details>
<p>Irrational Games was founded by a few ex-employees of <a href="https://en.wikipedia.org/wiki/Looking_Glass_Studios">Looking Glass Studios</a>,
which was a pioneer in the art of video games.
I think a large part of BioShock’s success can be traced to work done at Looking Glass.
Looking Glass is also <a href="https://en.wikipedia.org/wiki/Ion_Storm#Deus_Ex">linked</a> to the formation of Ion Storm Austin (Ion Storm itself being founded by <a href="https://en.wikipedia.org/wiki/Id_Software">id Software</a> founders, but that’s a rabbit hole for another time) and the development of <a href="https://en.wikipedia.org/wiki/Deus_Ex_(video_game)">Deus Ex</a>,
another critically acclaimed game of the era.</p>
<h2 id="looking-glass-studios-approach-to-game-design"><a href="#looking-glass-studios-approach-to-game-design">Looking Glass Studios’ approach to game design</a></h2>
<p>Looking Glass Studios produced three particularly influential games (plus sequels):
<a href="https://en.wikipedia.org/wiki/Ultima_Underworld:_The_Stygian_Abyss">Ultima Underworld (1992)</a>,
<a href="https://en.wikipedia.org/wiki/System_Shock">System Shock (1994)</a>,
and <a href="https://en.wikipedia.org/wiki/Thief:_The_Dark_Project">Thief (1998)</a>.
A big part of what makes these games great is the thought and effort that went into their game design fundamentals.</p>
<details open class="aside">
<summary>
Aside
</summary>
Seriously, some of the people at Looking Glass thought <em>hard</em> about game design.
<a href="https://en.wikipedia.org/wiki/Doug_Church">Doug Church</a> published <a href="https://www.gamedeveloper.com/design/formal-abstract-design-tools">this interesting article</a> about making game design more technical.
And <a href="https://en.wikipedia.org/wiki/Marc_LeBlanc">Marc LeBlanc</a> coined the <a href="https://en.wikipedia.org/wiki/Marc_LeBlanc#8_Kinds_of_Fun">8 kinds of fun</a> and has created a <a href="http://8kindsoffun.com/">wealth of materials on game design</a>.
</details>
<p>These games increasingly emphasise player agency and creativity.
Instead of relying on scripted sequences of events, the games have many independent systems that dynamically interact.
All the entities in the game are subject to the same set of rules, and the player is just one participant in this virtual world.
Challenges presented to the player don’t have a pre-determined solution, rather,
it’s up to the player to figure out how to use the systems at their disposal to overcome the challenge.
As the number of independent but interacting systems increase,
so do the number of solutions that the game developer never anticipated.
This style of game is now called an <a href="https://en.wikipedia.org/wiki/Immersive_sim">“immersive sim”</a>,
of which <a href="https://www.youtube.com/watch?v=kbyTOAlhRHk">Game Maker’s Toolkit has an entertaining overview</a>.</p>
<p>As <a href="https://www.raphkoster.com/">Raph Koster</a> puts it:</p>
<blockquote>
<p>If a problem basically has one answer, we often call it a puzzle.</p>
<p>Raph Koster — <a href="https://www.raphkoster.com/2025/11/03/game-design-is-simple-actually/">Game design is simple, actually – Raph Koster</a></p>
</blockquote>
<p>The immersive sim approach to game design eschews puzzles, and that’s part of why they’re my kind of fun.</p>
<p>The principles behind immersive sims appeal to me because of how they reflect real life.
Growing up I played a lot of RPG-style video games: fight enemies, gain experience points and items, level up, unlock skills, etc.
Looking back, I see that a big reason I was drawn to this sort of game was its simulation of progress.
Leveling up or crafting a rare item felt like an achievement at the time, but in hindsight it’s all hollow.
The levels I gained in some MMORPG are mostly just bits on a server somewhere; little evidence of them remains in me as a whole human being.
Growth of a virtual video game character was a cheap and low-risk simulacrum of personal growth that
lacked the lasting rewards.
After realising this, I started looking for games that reinforce skills I actually value,
thereby leaving a positive impression on <em>me</em>, instead of just increasing some numbers on a computer.
Immersive sims create opportunities for agency and creativity, which I generally value.</p>
<p><a href="https://en.wikipedia.org/wiki/Warren_Spector">Warren Spector</a>’s (Looking Glass Studios and Ion Storm) explanation for why immersive sims lack commercial success articulates precisely why they matter to me:</p>
<blockquote>
<p>it’s clear that there hasn’t been a huge immersive sim hit on par with some of the other video games out there.
I mean, we’re still waiting for the game that sells a gazillion copies!
I think part of the reason for that is that immersive sims require—or at least encourage—people to think before they act.
They tend not to be games where you just move forward like a shark and inevitably succeed.
In the best immersive sims, you have to assess the situation you’re in, make a plan and then execute that plan, dealing with any consequences that follow.
That’s asking a lot of players who basically have to do that every moment of their waking lives—in the real world, I mean.</p>
<p>Warren Spector — <a href="https://www.pcgamer.com/the-uncertain-future-of-games-like-deus-ex-and-dishonored/">The uncertain future of games like Deus Ex and Dishonored | PC Gamer</a></p>
</blockquote>
<p>I’m also intrigued by the way the immersive sim approach creates depth.
To me, depth is one of the components of art:
when you can continually go back to a work and experience it in new ways,
gradually uncovering more of what was there the whole time.</p>
<h2 id="tangent-old-websites"><a href="#tangent-old-websites">Tangent: old websites!</a></h2>
<p><a href="https://web.archive.org/">The Internet Archive</a> has
<a href="https://web.archive.org/web/20260000000000*/http://www.lglass.com/">snapshots</a>
of Looking Glass Studios’ website dating back to 1997.</p>
<p>Somehow I stumbled across their old
<a href="https://web.archive.org/web/19970625103015/http://www2.lglass.com/employee.html">employee home pages</a>.</p>
<p>Highlights:</p>
<ul>
<li><blockquote>
<p><a href="https://web.archive.org/web/19990128131802/http://brigit.lglass.com/%7Emahk/">Why the hell are you reading this?</a></p>
<ol type="1">
<li>I wandered here by accident. I’m lost.</li>
<li>I’m from the government, and I’m running a background check.</li>
<li>You’re dead, and I’m rummaging through your stuff.</li>
<li>I actually went looking for this page.</li>
<li>Why, I never! Who do you think you are?</li>
</ol>
</blockquote></li>
<li><blockquote>
<p><a href="https://web.archive.org/web/19970314211921/http://www2.lglass.com/~tjs/">The home of Tim Stellmach</a></p>
<p><strong>How am I like the Demiurge?</strong></p>
<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<thead>
<tr>
<th>Demiurge</th>
<th>Stellmach</th>
</tr>
</thead>
<tbody>
<tr>
<td>A creative, primeval diety</td>
<td>A creative, senior game designer</td>
</tr>
<tr>
<td>A feature of Gnostic theology</td>
<td>Said to have a great deal of “gnosis”</td>
</tr>
<tr>
<td>Said to be the “God” in the book of Genesis</td>
<td>Used to work for Origin Systems</td>
</tr>
<tr>
<td>Credited with creating the material world</td>
<td>Origin’s motto was “We Create Worlds”</td>
</tr>
</tbody>
</table>
</blockquote></li>
<li><blockquote>
<p><a href="https://web.archive.org/web/19990220072253/http://www.folded.com/jeff/">Not a Desert Mouse</a></p>
<p>The continuing adventures of a young man who, in fits of comic dementia, thinks he’s a
desert-dwelling rodent – and the crazy friends that surround him. Starring Jeff Yaus
as “Jeff”, the hapless twentysomething who keeps forgetting he’s in fact an urban primate.</p>
</blockquote></li>
</ul>
<p>I also found this image scattered around:</p>
<div style="width: 160px; margin: auto;">
<a href="http://www.cs.cmu.edu/~tilt/principia/"><img src="./images/pineal.gif"></a>
</div>
<p>which always links to <a href="http://www.cs.cmu.edu/~tilt/principia/">“the Principia Discordia”</a> (<a href="https://web.archive.org/web/19990508052433/http://www.cs.cmu.edu/%7Etilt/principia/">archived</a>).
Searching for “pineal web” turned up <a href="https://www.cs.cmu.edu/~tilt/pinealweb/">this page</a> (<a href="https://web.archive.org/web/19980122055107/http://www.cs.cmu.edu/~tilt/pinealweb/">archived</a>).
I wish this became a meme when Facebook was trying to make its “metaverse” happen.</p>
<p>It’s fascinatingly absurd.</p>
<p>On a (slightly) more serious note, I also found the original Thief website at
<a href="http://www.thief-thecircle.com/darkproj/" class="uri">http://www.thief-thecircle.com/darkproj/</a>.
It includes:</p>
<ul>
<li>A silly <a href="http://www.thief-thecircle.com/darkproj/band.html">credits page</a> (with a <a href="http://www.thief-thecircle.com/darkproj/headhunt.html">special version for recruiters</a>)</li>
<li>An entertaining <a href="http://www.thief-thecircle.com/darkproj/diarymonth.html">project diary</a> that spans 18 months of development</li>
<li>A brief <a href="http://www.thief-thecircle.com/darkproj/manifesto.html">rant about “computer role-playing games”</a></li>
</ul>
<p>I found it all quite inspiring.
It’s a reminder that you don’t need huge teams to make <em>good</em> games,
and even though you’re trying to be successful, you’re allowed to have fun on the way.</p>
<h2 id="why-i-took-so-long-to-finish-bioshock"><a href="#why-i-took-so-long-to-finish-bioshock">Why I took so long to finish BioShock</a></h2>
<p>BioShock has a <a href="https://en.wikipedia.org/wiki/Survival_horror">survival horror</a> feel to it,
which is a style of game I’ve never been fond of.
It has a creepy atmosphere with enough jump scares to keep you cautious,
so I was constantly stressed.
Not my kind of fun.
As a result, I procrastinated from playing it for over a year because I was rarely willing to handle that stress.
At the same time,
I was committed to finishing BioShock before I played another game,
so I was regularly reminded of my procrastination when friends recommended games to me.</p>
<p>About halfway though 2025 I began changing my life in a way conflicted with this procrastination:
forming the intention to do more “uncomfortable” things.</p>
<p>I had noticed that for a long time I’d been avoiding more and more uncomfortable things;
things that might bring up difficult emotions such as fear, sadness, or shame.
At the same time, I had become increasingly dissatisfied with my life and the direction I was heading.
I realised that the dissatisfaction was <em>caused</em> by my avoidance,
because the direction I <em>actually</em> want for my life requires me to continually confront unpleasant emotions.
By avoiding those emotions, I became stuck in a comfortable yet unsatisfying rut.</p>
<p>From this point of view, BioShock became an extremely low-stakes way to stop avoiding <em>something</em> and feel some unpleasant feelings.
One repetition of the kind of movement I need to get out of the rut.
I knew that the fear generated by playing the game was completely disconnected from the real world,
with no potential for negative consequences besides the feeling itself.
With that in mind, I resumed playing with the intention to feel the stress and fear instead of trying to minimise them.
I think this attitude actually made the game less stressful, because I wasn’t trying so hard to control my experience.
But it didn’t change the fear; the game was still creepy and scary, I just started moving towards the fear instead of hiding from it.
I had a similar opportunity more recently while playing a haunted house VR game at <a href="https://zerolatencyvr.com">Zero Latency</a>.
My instinct was to minimise my fear by staying away from suspicious places, looking away from creepy characters, and so on.
When I realised what I was doing, I decided to open myself to the experience and feel whatever came my way.
The game finished after I looked an ugly ghost-witch thing in the eyes as it rushed at me head on, to my character’s demise.</p>
<p>These experiences (plus a subsequent bungy jump) demonstrated that I really can handle the feelings I’m tempted to avoid.
In reality this was already the case (and always has been),
but when faced with potentially difficult emotions I can feel like they must be avoided at all costs,
as if experiencing it will be the end of me.
When I remember what it felt like to move towards the fear, feel it, and come out the other side, it widens my perspective.
That sense that the world is at stake decreases,
which gives me the freedom to
<a href="https://blog.ielliott.io/doing-the-right-thing">make the right choice</a>
even if I think it’ll be uncomfortable.</p>
<p>Now I’m starting to look at discomfort as simply the price of action,
and it’s the kind of transaction where trying to haggle or penny-pinch just makes everything worse.
My life so far has resulted in <em>this</em> body and mind, with specific capabilities, attachments and patterns of thought,
which sometimes means feeling bad is a <em>necessary</em> consequence of my actions:</p>
<ul>
<li>If I play through BioShock then I’ll often feel scared (because I’m just a bit sensitive)</li>
<li>If I lift a heavy weight then my muscles will hurt (because that’s how muscles generally work)</li>
<li>If I start a romantic relationship with someone then I’ll grieve the end of the relationship (because I’ve grown to love them)</li>
</ul>
<p>In the past I prioritised avoiding potential uncomfortable consequences.
I either lacked a vision of how I want my life to be (so “feeling good” became the placeholder)
or put my short-term comfort ahead of whatever vision I had.
Now I’m paying more attention to what I actually want for myself, and then pursuing it with a willingness to pay whatever price is actually required.</p>
    ]]></content>
    
</entry>
<entry>
    <title>Doing the "right" thing</title>
    <link href="https://blog.ielliott.io/doing-the-right-thing" />
    
    <id>https://blog.ielliott.io/doing-the-right-thing</id>
    
    <published>2026-03-05T05:30:00Z</published>
    <updated>2026-03-05T05:30:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/doing-the-right-thing"><![CDATA[<p>
Over the course of this decade, when faced with a choice I've often wondered which option is the "right" one for me.
I've been learning that I usually think this way as an attempt to soothe my anxiety about the potential negative outcomes of my decision.
In this mindset, the "right" choice is the one that has the least downsides.
Even when I'm trying to maximise an outcome, focusing on what I stand to gain rather than lose, underneath I'm still trying to avoid suffering a less-then-optimal result.
</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/doing-the-right-thing"><![CDATA[
      
      <p>Over the course of this decade, when faced with a choice I’ve often wondered which option is the “right” one for me.
I’ve been learning that I usually think this way as an attempt to soothe my anxiety about the potential negative outcomes of my decision.
In this mindset, the “right” choice is the one that has the least downsides.
Even when I’m trying to maximise an outcome, focusing on what I stand to gain rather than lose, underneath I’m still trying to avoid suffering a less-then-optimal result.</p>
<p>This doesn’t work in the long run, because all decisions involve letting go of something.
If I turn left, then I’ve declined the opportunity to have turned right.
Decisions feel difficult when the options trade off between things I value; no matter what I decide, I’ll still lose something that matters.
On top of that, there are all the potential negatives that I’m imagining which (upon reflection) probably won’t come to pass, but in the moment feel extremely important to account for.
Personally, trying to minimise negative consequences is fraught.</p>
<p>Now I’m trying to improve my decision-making process by being less evaluative and more intuitive.
I’ve found that there’s a kind of “right”ness that I can know without thinking.
If I’m out getting a snack and I notice an opportunity to walk away without paying, I’ll still pay anyway.
My decision to not steal isn’t due to the fear of the potential consequences of stealing, or the outcome of a cost-benefit analysis.
In that moment paying is simply the “right” choice, and it’s a conclusion which requires no thought.
If you ask me <em>why</em> I didn’t steal the snack, I could give you some reasons that would reveal some of my values and worldview.
But the knowing came <em>before</em> the justification.</p>
<p>When I look at all the decisions I’m faced with in a day, I see that most of them have an intuitively “right” choice.
But it’s not always easy to make do the “right” thing in the moment.
The main difficulty is dealing with all the other things I want at the time of the decision.
Suppose it’s time for lunch and I have a healthy home-cooked meal in the fridge, but I’m also craving a pizza.
For me the intuitively “right” choice is to eat the home-cooked meal for lunch, but it’s <em>hard</em> to do that while I’m craving a pizza.
I don’t exactly enjoy doing the harder thing when faced with this kind of difficulty, but I’m starting to realise that the easier alternative is a trap.
At face value “doing the right thing, but it’s hard” and “doing a not-right thing, but it’s comfortable and easy” seem like they trade off equally against each other,
but I’ve found that in the long run the former encourages flourishing while the latter leads to stagnation and suffering.
Having noticed this, I’ve started embracing difficulty by saying to myself, “I’m not here for an easy time”.
I need the strength to do the “right” thing even when it feels hard.</p>
<p>Another difficulty with making the “right” choice is actually recognising that there are options.
From the inside, habits and routines feel choiceless.
When I’m doing something habitually I’m usually not aware of alternatives, so there’s no opportunity choose the “right” one.
It’s as if the choice was made some time in the past by the process that formed the habit.
One way I’m working on this is by trying to be aware more often, kind of like a constant meditation.
The habits still run but awareness allows me to override them when I realise something’s not “right”.</p>
<p>I’m also taking more time to reflect, by journaling.
The next step is to ask, “What have I been taking as given, and should it be different somehow?”
Intuition can provide the “right” answer to this question.
Even then, there will still be possibilities I can’t conceive of alone, so a further step is to work on this question with other people.
Intuition is used to judge and transform the answers other people generate.</p>
<p>These thoughts were inspired by the lecture <a href="https://www.youtube.com/watch?v=MbJ-zU43WaY">Procrastination Holds You Back - YouTube</a>.</p>
    ]]></content>
    
</entry>
<entry>
    <title>2025 Project Review</title>
    <link href="https://blog.ielliott.io/2025-project-review" />
    
    <id>https://blog.ielliott.io/2025-project-review</id>
    
    <published>2026-02-07T21:55:00Z</published>
    <updated>2026-02-07T21:55:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/2025-project-review"><![CDATA[<p>Reflections on 2025's hobby projects.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/2025-project-review"><![CDATA[
      
      <div id="toc">
<h3>Contents</h3>
<ul>
<li><a href="#blog">Blog</a></li>
<li><a href="#type-passing-compilation">Type-passing compilation</a></li>
<li><a href="#mdpreview"><code>mdpreview</code></a></li>
<li><a href="#lastpass-to-keepassxc-migration">LastPass to KeepassXC migration</a></li>
<li><a href="#gmail-to-fastmail-migration">GMail to Fastmail migration</a></li>
<li><a href="#devops-practise">Devops practise</a></li>
<li><a href="#feeds-for-youtube-subscriptions">Feeds for YouTube subscriptions</a></li>
<li><a href="#gen-alias"><code>gen-alias</code></a></li>
<li><a href="#pdf-form-filling-web-app">PDF form filling web app</a></li>
<li><a href="#learning-pdf">Learning PDF</a></li>
<li><a href="#talk-a-third-way-of-compiling-polymorphism">Talk: A “third way” of compiling polymorphism</a></li>
<li><a href="#experimental-templating-language">Experimental templating language</a></li>
<li><a href="#mdtest"><code>mdtest</code></a></li>
<li><a href="#type-safe-web-routing">Type-safe web routing</a></li>
<li><a href="#datalog-adventures">Datalog adventures</a></li>
<li><a href="#pharmacy-report-generator">Pharmacy report generator</a></li>
<li><a href="#system-font-fixes">System font fixes</a></li>
<li><a href="#diagnostica-and-diagnostica-sage-improvements"><code>diagnostica</code> and <code>diagnostica-sage</code> improvements</a></li>
<li><a href="#smalltalk">Smalltalk</a></li>
<li><a href="#mtl-patch"><code>mtl</code> patch</a></li>
<li><a href="#hdeps"><code>hdeps</code></a></li>
<li><a href="#sage-fixes"><code>sage</code> fixes</a></li>
<li><a href="#tsk"><code>tsk</code></a></li>
<li><a href="#mdlink"><code>mdlink</code></a></li>
<li><a href="#syncthing-merge-and-asker"><code>syncthing-merge</code> and <code>asker</code></a></li>
<li><a href="#rand"><code>rand</code></a></li>
</ul>
</div>
<h2 toc:omit_children="true" id="blog"><a href="#blog">Blog</a></h2>
<p><em>ongoing</em></p>
<h3 id="posts"><a href="#posts">Posts</a></h3>
<ul>
<li><a href="/removing-disqus">Removing Disqus</a></li>
<li><a href="/smalltalk-and-lambda-calculus">Smalltalk and Lambda Calculus</a></li>
<li><a href="/haskell-foldable-quiz">A Haskell "Foldable" quiz</a></li>
<li><a href="/paying-for-keepassxc">Paying for KeePassXC</a></li>
<li><a href="/exploring-graphs-with-prolog">Exploring a dependency graph with Prolog</a></li>
<li><a href="/context-menus">Context menus</a></li>
<li><a href="/playing-with-ghc-package-databases">Playing with GHC package databases</a></li>
<li><a href="/my-git-cli-overhaul">My Git CLI overhaul</a></li>
<li><a href="/in-praise-of-zsa">In Praise of ZSA</a></li>
</ul>
<p>I wrote more posts this year than I did last year.
I’ve decided that I want to post interesting thoughts that either don’t work as articles or that I’m just not interested in expanding on too much.
The idea is to lower the standard of what’s shareable so that I share more often.
This is inspired by my slow retreat from popular social media;
I want to retain a presence on the Web, but on my own terms.
Posting on my own site is the best way to do that.</p>
<h3 id="site-improvements"><a href="#site-improvements">Site improvements</a></h3>
<ul>
<li><p>Restyle</p>
<div style="display: flex; flex-direction: row; gap: 1rem;">
<figure>
<a href="images/20260111-site-restyle-before.png" target="_blank"><img src="images/20260111-site-restyle-before.png"></a>
<figcaption>
Before
</figcaption>
</figure>
<figure>
<a href="images/20260111-site-restyle-after.png" target="_blank"><img src="images/20260111-site-restyle-after.png"></a>
<figcaption>
After
</figcaption>
</figure>
</div>
<p>Cleaned things up and improved content density.
I also removed Google Analytics and Fonts.</p></li>
<li><p><a href="https://github.com/LightAndLight/lightandlight.github.io?tab=readme-ov-file#replies">“Reply” content type</a></p>
<p>This content type is for short responses and thoughts.
I originally added it so that I could make a <a href="https://blog.ielliott.io/reply/202508052146">short comment</a> that responding to a section of a previous post.
Later I made “referencing a previous post” optional so that I could write a <a href="https://blog.ielliott.io/note/202508160025">standalone note</a>.</p>
<!-- TODO: note about how I want distributed "social media"? --></li>
</ul>
<h2 id="type-passing-compilation"><a href="#type-passing-compilation">Type-passing compilation</a></h2>
<p><em>January</em></p>
<p><a href="https://github.com/LightAndLight/type-passing-compilation" class="uri">https://github.com/LightAndLight/type-passing-compilation</a> (private)</p>
<p>Starts implementing the idea I wrote about in <a href="https://blog.ielliott.io/2023-project-review#low-level-ir-compiler">2023 Project Review: Low-level IR compiler</a>.
The gist is: passing around <a href="https://en.wikipedia.org/wiki/Virtual_method_table">vtables</a> of memory manipulation functions for polymorphic types,
instead of monomorphising or forcing everything to be heap-allocated.</p>
<p>I stalled while thinking about support for higher-kinded polymorphism.
It requires allocating new vtables at runtime,
which felt kind of complicated so I was hesitant to commit to it.
The point of this project, though, is to find out whether that sort of runtime cost is worth it.
So I really just need to find a way to simplify what I’m trying to build so that I can test it.</p>
<p>At <a href="https://zfoh.ch/zurihac2025/">ZuriHac</a> people reminded me of <a href="https://github.com/ollef/sixten">Sixten</a>,
which passes around sizes instead of a full vtable.
I think this works because Sixten uses a <a href="https://en.wikipedia.org/wiki/Boehm_garbage_collector">tracing garbage collector</a>,
so it can treat pointers as regular data and just copy them around.
I’d like my version to support reference counting,
which means the behaviour of copying data depends on the type.
For example, simple types are just <code>memcpy</code>ed, whereas copying a pointer also needs to increment a reference count.</p>
<p>See also: <a href="#talk-a-third-way-of-compiling-polymorphism">Talk: A “third way” of compiling polymorphism</a></p>
<h2 id="mdpreview"><a href="#mdpreview"><code>mdpreview</code></a></h2>
<p><em>January</em></p>
<p><a href="https://github.com/LightAndLight/personal-configs/tree/533bc27168fc155b56ed055294b9feda06308733/system/packages/mdpreview" class="uri">https://github.com/LightAndLight/personal-configs/tree/533bc27168fc155b56ed055294b9feda06308733/system/packages/mdpreview</a></p>
<p><code>mdpreview</code> is a script that translates a Markdown document to HTML.
It’s an easy way to render a Markdown file to check I’ve formatted it correctly.
It creates a new HTML file every time it’s run, so one improvement would be to have it watch a file and re-render on change, so that I can just refresh page after editing to view the changed document.</p>
<h2 id="lastpass-to-keepassxc-migration"><a href="#lastpass-to-keepassxc-migration">LastPass to KeepassXC migration</a></h2>
<p><em>January–June</em></p>
<ul>
<li><a href="https://blog.ielliott.io/paying-for-keepassxc" class="uri">https://blog.ielliott.io/paying-for-keepassxc</a></li>
<li><a href="https://github.com/LightAndLight/personal-configs/blob/533bc27168fc155b56ed055294b9feda06308733/home/keepassxc.nix" class="uri">https://github.com/LightAndLight/personal-configs/blob/533bc27168fc155b56ed055294b9feda06308733/home/keepassxc.nix</a></li>
</ul>
<p>I moved all my account information from LastPass to a local KeepassXC database.
I changed hundreds of passwords, which was very boring, but now I’m glad that I did it.
One of my favourite things about using a normal program (rather than a web app) is that it’s subject to <em>way</em> less churn.
It feels like these big web app “software as a service” companies are always tweaking, fiddling, and breaking things.
With a normal program, I can choose when to update it, if ever.</p>
<p>I also submitted a <a href="https://github.com/keepassxreboot/keepassxc/pull/12236">patch</a> to KeepassXC
to make it work better with <a href="https://nix-community.github.io/home-manager/">home-manager</a>,
which was included in KeepassXC version 2.7.11 and NixOS 25.11.
If this was a closed source or web program, I wouldn’t have been able to fix it myself.</p>
<p>To access my passwords from my mobile phone,
I use <a href="https://syncthing.net/">Syncthing</a> with <a href="https://github.com/researchxxl/syncthing-android">Syncthing-Fork / syncthing-android</a> to sync the password database,
and <a href="https://github.com/Kunzisoft/KeePassDX">KeepassDX</a> to read the database on the phone.
I’m considering setting up a small server to make syncing a bit easier.</p>
<h2 id="gmail-to-fastmail-migration"><a href="#gmail-to-fastmail-migration">GMail to Fastmail migration</a></h2>
<p><em>February</em></p>
<p>I’m slowly moving my data away from Google, and I decided to work on my emails first.
This year I’ll probably do file storage.</p>
<p>I briefly looked into running my own email server, but I got the impression that the current email ecosystem is hostile toward new/small servers.
After deciding not to mess around with that stuff, I tried <a href="https://www.fastmail.com/">Fastmail</a>.
Their free trial month went by without any issues so I bought a yearly subscription.</p>
<p>I use the <a href="https://www.thunderbird.net/">Thunderbird</a> email client instead of the Fastmail web client (you might notice a pattern here).
I’m not very satisfied by Thunderbird, but it’s good enough for now.
It could be fun to write my own email client one day.</p>
<h2 id="devops-practise"><a href="#devops-practise">Devops practise</a></h2>
<p><em>March</em></p>
<p><a href="https://github.com/LightAndLight/infra" class="uri">https://github.com/LightAndLight/infra</a> (private)</p>
<p>I played around with using <a href="https://github.com/getsops/sops">SOPS</a> to encrypt <a href="https://opentofu.org/">Terraform/Tofu</a> state so that I can version it in Git.
I like this approach more than e.g. setting up object storage somewhere to use as a Terraform backend.</p>
<h2 id="feeds-for-youtube-subscriptions"><a href="#feeds-for-youtube-subscriptions">Feeds for YouTube subscriptions</a></h2>
<p><em>March</em></p>
<ul>
<li><a href="https://lectio.news/" class="uri">https://lectio.news/</a></li>
<li><a href="https://news.ycombinator.com/item?id=44412109" class="uri">https://news.ycombinator.com/item?id=44412109</a></li>
</ul>
<p>I created a service that turns my YouTube subscriptions into an RSS/Atom feed.</p>
<p>I have two problems with YouTube’s website and apps:</p>
<ol type="1">
<li>They’re extremely distracting; full of ads and recommendations</li>
<li>It’s yet one more “thing” to check and I can’t be bothered</li>
</ol>
<p>Putting my YouTube subscriptions into my feed reader solved these problems for me,
and I’m extremely satisfied with the result.
Now when I open up my feed reader I see who’s written new articles, <em>and</em> whether YouTube channels I’ve subscribed to have uploaded new videos.
I then get to decide whether to read an article or watch a video.</p>
<p>I was surprised by the rate of new uploads for my YouTube subscriptions.
A lot of them are TikTok-style short videos, which I think is a bit gross.
Fortunately the feed just shows me the title, duration, and description, which gives me a dense summary of many videos and makes it easier to decide what not to watch.
In contrast, I find the “swipe through auto-playing portrait-orientation short videos” interface to be an extremely slimy design pattern.
It’s like gambling with your attention, <em>hoping</em> that the next one will be something you actually wanted to see.</p>
<p>Currently the code for this service is private because I’m curious whether anyone would like to pay for it.</p>
<h2 id="gen-alias"><a href="#gen-alias"><code>gen-alias</code></a></h2>
<p><em>March</em></p>
<p><a href="https://github.com/LightAndLight/gen-alias" class="uri">https://github.com/LightAndLight/gen-alias</a></p>
<p>After switching to Fastmail I learned of their <a href="https://www.fastmail.help/hc/en-us/articles/4406536368911-Masked-Email">masked email</a> feature.
1Password and Bitwarden support generating masked emails (<a href="https://www.fastmail.com/blog/masked-email-from-fastmail-and-1password-protects-your-identity-online/">1</a>, <a href="https://www.fastmail.com/blog/masked-email-now-in-more-places-with-bitwarden-integration/">2</a>) via
a <a href="https://www.fastmail.com/dev/#:~:text=Masked%20Email%20API">JMAP API</a>,
but KeepassXC doesn’t.
I wrote a program that used the JMAP API directly and realised that I didn’t like the format of the masked emails it generated.
I wanted <code>{service}.{randomId}@{domain}</code>, but the Fastmail API doesn’t allow <code>.</code> in the masked email prefix.
I wrote <code>gen-alias</code> to work around this.</p>
<p>I set up a subdomain of <code>ielliott.io</code> with my Fastmail MX records specifically for these unique email addresses.
I configured Fastmail to send <code>*@{subdomain}.ielliott.io</code> to my main mailbox.
When an online service needs an email address, I use <code>gen-alias</code> to generate <code>{service}.{randomId}@{subdomain}.ielliott.io</code>,
which I paste into my password manager and the online form.</p>
<p>I really like this setup; it’s already helped me identify services that attract spam.
My main source of spam in 2025 was via my GitHub profile.
Second to that was software development consultant spam to an email address that was on <a href="https://lectio.news">a page</a> I <a href="https://news.ycombinator.com/item?id=44412109">submitted to Hacker News</a>.</p>
<h2 id="pdf-form-filling-web-app"><a href="#pdf-form-filling-web-app">PDF form filling web app</a></h2>
<p><em>April</em></p>
<p>This was my first real contracting gig!
The business I worked with constantly fills out PDF forms that are published by the Australian Govenment.
Some information, such as identity or contact details, is repeated across many forms.
I prototyped a web app that allows the user to auto-fill many of the form fields, enter the remaining fields manually, then generate the PDF.</p>
<p>The official PDFs have (mostly working) form field annotations, so PDF viewers render the documents with interactive fields.
I created a “mapping” format that describes field types (text, multiple-choice, etc.), and the relationship between the logical form fields and the PDF form field annotations.
Most of the mapping can be automatically generated from a PDF,
after which can be used to render the web version of the form (e.g. so that you don’t create a HTML text field for a checkbox field),
and insert/extract data into/from the corresponding PDF.</p>
<p>I enjoyed working on such an obviously useful project.
One frustrating part of my career so far is how often companies have lacked clarity in the problems they’re solving or the product they’re creating.
This shows up as: trying to measure user engagement with features (“We’re not sure what we want so let’s build a few things and see what users like.”),
factions competing for product direction (“What do you mean ‘We’re building an X.’? We’re building a Y!”),
or “bottom-up” development (“Hey team, each of you gets to decide what you want this to be.”).
That’s not really my style; I prefer to form an opinion of what to create and then bring that into the world.
In this project, the core idea was solid with no room for equivocation, and it was my job to make it happen.</p>
<h2 id="learning-pdf"><a href="#learning-pdf">Learning PDF</a></h2>
<p><em>April</em></p>
<p><a href="https://github.com/LightAndLight/pdf" class="uri">https://github.com/LightAndLight/pdf</a> (private)</p>
<p>In the PDF form filling web app I used <a href="https://pypdf.readthedocs.io/en/stable/"><code>pypdf</code></a> for PDF manipulation,
because I didn’t trust that there’d be an easy-to-use Haskell PDF library.
After I finished, I tried writing my own Haskell PDF library based on
<a href="https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf">the PDF 1.7 spec</a>.
I made some progress, including support for compressed streams objects and password-based encryption,
but I don’t plan to turn it into something publicly usable.</p>
<p>PDF internals are pretty interesting.
It’s a texual format, and there’s syntax for values like booleans, integers, dictionaries, etc.
There’s also a way to reference to values defined elsewhere in the document.
One cool part of the design is that PDFs are read by seeking to the end of the file and working backwards.
This way a document can be revised by appending to the file.
If you want to know more,
<a href="https://commandlinefanatic.com/cgi-bin/showarticle.cgi?article=art019">Inside the PDF File Format</a> is good introduction.</p>
<h2 id="talk-a-third-way-of-compiling-polymorphism"><a href="#talk-a-third-way-of-compiling-polymorphism">Talk: A “third way” of compiling polymorphism</a></h2>
<p><em>April</em></p>
<ul>
<li><a href="https://github.com/LightAndLight/polymorphism-third-way-talk">source</a></li>
<li><a href="https://blog.ielliott.io/talks/polymorphism-third-way.pdf">slides</a></li>
</ul>
<p>I presented the ideas behind <a href="#type-passing-compilation">type-passing compilation</a> at the <a href="https://bfpg.org/">Brisbane Functional Programming Group</a>.</p>
<h2 id="experimental-templating-language"><a href="#experimental-templating-language">Experimental templating language</a></h2>
<p><em>May</em></p>
<p><a href="https://github.com/LightAndLight/tpl" class="uri">https://github.com/LightAndLight/tpl</a> (private)</p>
<p>I played around with a template language like <a href="https://mustache.github.io/">Mustache</a> or <a href="https://jinja.palletsprojects.com/en/stable/">Jinja</a>.</p>
<p>There were two new things I wanted to try:</p>
<ul>
<li><p>Explicitly defined, typed template variables</p>
<p>For example, instead of writing</p>
<pre><code>Hello, {name}!</code></pre>
<p>you’d write</p>
<pre><code>{% require name %}
Hello, {name}!</code></pre>
<p>This lets you easily ask a template what kind of variables it needs.</p></li>
<li><p>Expression-oriented substitution</p>
<p>In Mustache or Jinja, to subsitute a list you need use an open tag and closing tag:</p>
<p>Mustache:</p>
<pre><code>&lt;ul&gt;{{#list_of_things}}
  &lt;li&gt;{{list_item}}&lt;/li&gt;
{{/list_of_times}}&lt;/ul&gt;</code></pre>
<p>Jinja:</p>
<pre><code>&lt;ul&gt;{% for list_item in list_of_things %}
  &lt;li&gt;{{ list_item }}&lt;/li&gt;
{% endfor %}&lt;/ul&gt;</code></pre>
<p>I want to use <code>{}</code> for substitution, and push iteration into an expression.
Something like:</p>
<pre><code>&lt;ul&gt;{for list_item in list_of_things yield &lt;li&gt;{list_item}&lt;/li&gt;}&lt;/li&gt;</code></pre></li>
</ul>
<p>I was also curious what it would look like to write a high-performance bytecode interpreter for these templates,
and how that should be integrated into a web server.
For example, maybe the server could precompile all the templates on startup.</p>
<h2 id="mdtest"><a href="#mdtest"><code>mdtest</code></a></h2>
<p><em>May</em></p>
<p><a href="https://github.com/LightAndLight/mdtest" class="uri">https://github.com/LightAndLight/mdtest</a></p>
<p><code>mdtest</code> was inspired by the way I wrote the spec for the experimental template language above.
I created a Markdown document with code blocks that mimicked a command line: a command followed by the expected output.
<code>mdtest</code> runs such code blocks and prints a summary.</p>
<p>Here’s what it prints when run against the project’s
<a href="https://github.com/LightAndLight/mdtest?tab=readme-ov-file#mdtest">README</a>:</p>
<figure>
<img src="images/20260201-mdtest-output.png" style="max-width: 400px;">
<figcaption>
Screenshot of my terminal’s <code>mdtest</code> output
</figcaption>
</figure>
<h2 id="type-safe-web-routing"><a href="#type-safe-web-routing">Type-safe web routing</a></h2>
<p><em>July</em></p>
<p><a href="https://github.com/LightAndLight/misc/tree/main/20250704-faster-typesafe-web-routing" class="uri">https://github.com/LightAndLight/misc/tree/main/20250704-faster-typesafe-web-routing</a></p>
<p>A simplified version of <a href="https://blog.ielliott.io/2024-project-review#functional-web-routing" class="uri">https://blog.ielliott.io/2024-project-review#functional-web-routing</a>.
Sketches a type-safe approach to <a href="https://hackage.haskell.org/package/scotty"><code>scotty</code></a>-style web servers.
At it’s core it contains a trie-like data structure for routing.
In addition to routing web requests, the trie can be used to render a sitemap or API schema.
It can also be used to render type-safe URLs.</p>
<p>I don’t remember what this is supposed to be faster than, though.</p>
<h2 id="datalog-adventures"><a href="#datalog-adventures">Datalog adventures</a></h2>
<p><em>August</em></p>
<ul>
<li><a href="https://blog.ielliott.io/exploring-graphs-with-prolog" class="uri">https://blog.ielliott.io/exploring-graphs-with-prolog</a></li>
<li><a href="https://github.com/LightAndLight/misc/tree/main/20250806-datalog" class="uri">https://github.com/LightAndLight/misc/tree/main/20250806-datalog</a></li>
</ul>
<p>I learned that logic programming languages can be used to query databases.
My first time around I translated my data into a big Prolog file and which I imported into the Prolog REPL to write queries against.
Then I wrote my own Datalog-inspired system to learn about how these systems really work.
<a href="http://webdam.inria.fr/Alice/">Foundations of Databases</a> was an excellent (and freely available) textbook for this adventure.</p>
<p>The Datalog-style approach to relational databases feels more elegant than SQL.
I’d like to take it a bit more seriously in the future.</p>
<h2 id="pharmacy-report-generator"><a href="#pharmacy-report-generator">Pharmacy report generator</a></h2>
<p><em>August</em></p>
<p>I have a close friend who works at a pharmacy, and part of their job is to create weekly reports (as spreadsheets) for doctors,
with updates about the status of patents’ prescriptions.
They spent hours each week doing this by hand.
I wrote a Python program using <a href="https://beeware.org/">BeeWare</a> that reads CSV files and generates the spreadsheet reports.
It saves them hours every week and they’ve thanked me several times :)</p>
<p>The program is configured in <a href="https://github.com/hashicorp/hcl?tab=readme-ov-file#hcl">HCL</a>,
so the processing can be changed as new doctors come on board or column formatting requirements change.
My friend is not a programmer, but they’re not helpless either, so they’ve been able to learn how to change the config format to achieve their goals.
When they’re unsure they double-check with me.
The next step would be to create a GUI for the config so that it’s easier to change.</p>
<h2 id="system-font-fixes"><a href="#system-font-fixes">System font fixes</a></h2>
<p><em>August</em></p>
<ul>
<li><a href="https://github.com/LightAndLight/personal-configs/blob/533bc27168fc155b56ed055294b9feda06308733/system/fonts.nix#L4-L25" class="uri">https://github.com/LightAndLight/personal-configs/blob/533bc27168fc155b56ed055294b9feda06308733/system/fonts.nix#L4-L25</a></li>
<li><a href="https://github.com/LightAndLight/personal-configs/blob/533bc27168fc155b56ed055294b9feda06308733/machines/desktop/default.nix#L26" class="uri">https://github.com/LightAndLight/personal-configs/blob/533bc27168fc155b56ed055294b9feda06308733/machines/desktop/default.nix#L26</a></li>
<li><a href="https://github.com/LightAndLight/personal-configs/blob/533bc27168fc155b56ed055294b9feda06308733/machines/thinkpad-x1-carbon-gen12/default.nix#L39" class="uri">https://github.com/LightAndLight/personal-configs/blob/533bc27168fc155b56ed055294b9feda06308733/machines/thinkpad-x1-carbon-gen12/default.nix#L39</a></li>
</ul>
<p>Firstly, I did a bunch of config-wrangling on NixOS to fix my font stack.
I discovered that some common fonts that websites assumed would be on my system were missing (e.g. Georgia/Gelasio) or failing to match (Linux Libertine/Linux Libertine O).
After that I went a bit overboard and set my fonts to roughly the same perceptual size across my desktop and laptop.
The physical font size on my laptop is smaller than that of my desktop,
but appears similar to my desktop’s font size because my laptop screen is closer.</p>
<h2 id="diagnostica-and-diagnostica-sage-improvements"><a href="#diagnostica-and-diagnostica-sage-improvements"><code>diagnostica</code> and <code>diagnostica-sage</code> improvements</a></h2>
<p><em>September</em></p>
<ul>
<li><a href="https://github.com/LightAndLight/diagnostica" class="uri">https://github.com/LightAndLight/diagnostica</a></li>
<li><a href="https://github.com/LightAndLight/diagnostica-sage" class="uri">https://github.com/LightAndLight/diagnostica-sage</a></li>
</ul>
<p><code>diagnostica</code> is my CLI error diagnostics library.
I started writing a Haskell HCL parser after working on the Pharmacy report generator and I used <code>diagnostica</code> to render syntax errors.</p>
<p>I found that <code>diagnostica</code> only worked properly for ASCII documents,
displaying errors incorrectly in the presence of &gt;1 byte UTF-8 characters.
It was easy to fix, but there’s a related issue which I haven’t yet addressed.
<code>diagnostica</code> uses the <code>^</code> character to “underline” some text,
but that only works when the number of glyphs displayed on the line above matches the number of Unicode code points.
When a font or <a href="https://harfbuzz.github.io/why-do-i-need-a-shaping-engine.html">text shaper</a> combines adjacent characters,
<code>diagnostica</code> generates too many <code>^</code>s.
I think the right way to fix this would be to remove the <code>^</code>s altogether and emit an <a href="https://en.wikipedia.org/wiki/ANSI_escape_code#:~:text=underline">underline escape sequence</a> instead.</p>
<h2 id="smalltalk"><a href="#smalltalk">Smalltalk</a></h2>
<p><em>September</em></p>
<p><a href="https://blog.ielliott.io/smalltalk-and-lambda-calculus" class="uri">https://blog.ielliott.io/smalltalk-and-lambda-calculus</a></p>
<p>I got curious about Smalltalk after listening to someone talk about <a href="https://en.wikipedia.org/wiki/Gleam_(programming_language)">the Gleam programming language</a>.
Gleam adds types to many of Erlang’s patterns, so I was thinking about Erlang and realised that Erlang processes are essentially objects in the Smalltalk sense.</p>
<p>I started wondering what else can be thought of as an object.
The first interesting answer was: web servers.
I installed <a href="https://pharo.org/">Pharo</a> and managed to write some code that turned any Smalltalk object into a web server.
It was surprisingly easy, and I suppose that’s because what I wanted to do was consistent with the Smalltalk design ethos.</p>
<p>After that, I kept playing with Pharo because I wanted to get a better sense of what it’s like to write code “the Smalltalk way”.
I wrote a lambda calculus interpreter.
As part of that project I wrote a parser combinator library, which fit quite well into the Smalltalk paradigm.
Think of a primitive, such as <code>satisfy : (Char -&gt; Bool) -&gt; Parser Char</code>, as a “cell” whose only responsibility is parsing a character that satisfies the predicate.
Then a combinator like <code>(&lt;*&gt;) : Parser (a -&gt; b) -&gt; Parser a -&gt; Parser b</code> is a way to create a bigger cell that delegates work to two smaller cells then combines the result.
In the end, a grammar is an intricate network of cells that work together to parse some text.
It worked out great, and I think that’s because parser combinators are implemented using functions, which are a simple kind of object (an objects are a special kind of function).</p>
<p>I also thought a lot about the role of <em>data</em> (as opposed to <a href="https://en.wikipedia.org/wiki/Coinduction">codata</a>) in an object-oriented language.
In Smalltalk, everything is an object, so everything is coinductively defined.
You can still define datatypes via <a href="https://en.wikipedia.org/wiki/Church_encoding">Church encoding</a>,
but what if that’s not idiomatic; just a trick to express an idiom from other programming environments?</p>
<p>My conclusion is that data is still necessary.
Smalltalk emphasises late binding: the recipient of a message decides how to respond.
This adds flexibility, because the receiver can its behaviour without while the code that sends the message remains the same.
Data allows late binding the “interpretation” of something.
When you define a datatype you may have a couple of use cases in mind, like a syntax tree that you can print or evaluate.
But there’s an infinite number of ways that other people might want to use that data, such as simplifying the syntax tree or calculating some statistics about it.
Data is the most flexible representation of structure,
allowing the holder of the data decide on an interpretation without modifying the definition of the data structure.</p>
<h2 id="mtl-patch"><a href="#mtl-patch"><code>mtl</code> patch</a></h2>
<p><em>October</em></p>
<p><a href="https://github.com/haskell/mtl/pull/171" class="uri">https://github.com/haskell/mtl/pull/171</a></p>
<p>An <a href="https://hackage.haskell.org/package/mtl"><code>mtl</code></a> maintainer pinged me on an <a href="https://github.com/haskell/mtl/issues/84">issue I created years ago</a>,
so I submitted a patch for it.
The change adds instances for the
<a href="https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Data-Functor-Product.html#t:Product">functor product</a>.</p>
<p>The original motivation for this was to test “records of functions”.
If you have some overloaded effectful operations:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Ops</span> m</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">Ops</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> op1 ::</span> <span class="dt">A</span> <span class="ot">-&gt;</span> m <span class="dt">B</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> op2 ::</span> <span class="dt">C</span> <span class="ot">-&gt;</span> m <span class="dt">D</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">...</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
<p>then you may end up writing a derived overloaded operation that uses an MTL type class:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ot">derivedOp ::</span> <span class="dt">MonadError</span> <span class="dt">YourError</span> m <span class="ot">=&gt;</span> <span class="dt">Ops</span> m <span class="ot">-&gt;</span> <span class="dt">X</span> <span class="ot">-&gt;</span> m <span class="dt">Y</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>derivedOp <span class="ot">=</span> <span class="op">...</span></span></code></pre></div>
<p>Using the functor product, two <code>Ops</code> can be combined into a single <code>Ops</code> that runs two operations in lockstep:</p>
<pre><code>pairOps :: Ops m -&gt; Ops n -&gt; Ops (Product m n)
pairOps m n =
  Ops
    { ops1 = \a -&gt; Pair (ops1 m) (ops1 n)
    , ops2 = \c -&gt; Pair (ops2 m) (ops2 n)
    , ...
    }</code></pre>
<p>You can then write tests that calls a function from <code>Ops (Product m n)</code> and compares the outputs on each side of the pair.
If you want to test a function like <code>derivedOp</code> in this way then you need an instance for <code>MonadError e (Product m n)</code>.</p>
<h2 id="hdeps"><a href="#hdeps"><code>hdeps</code></a></h2>
<p><em>October</em></p>
<p><a href="https://github.com/LightAndLight/hdeps" class="uri">https://github.com/LightAndLight/hdeps</a></p>
<p><code>hdeps</code> is a tool that makes it easy to override Haskell dependencies in <a href="https://github.com/NixOS/nixpkgs"><code>nixpkgs</code></a>.</p>
<p>Sometimes I have a project that builds with Cabal,
then discover that the <code>nixpkgs</code> version I want to build my project against has a Haskell package set that’s incompatible with the version bounds on my transitive dependencies.
When this happens, I don’t want to fork a bunch of packages just to twiddle with their version bounds.
Instead, I want to tell Nix to use the versions of Haskell packages that I know are already working.
<code>hdeps</code> makes this super easy.</p>
<p>It reads a manifest that says,
“get this package version from Hackage, that package version from GitHub, etc.”
and generates a Nix overlay that can be used to extend <code>nixpkgs</code>’s Haskell package set.
It can also manage your <code>cabal.project</code> file to ensure that your Cabal builds use the same packages that are in the overlay.</p>
<p>I’m curious what it’d be like to generate the Nix overlay using Cabal’s <a href="https://hackage.haskell.org/package/cabal-plan"><code>plan.json</code></a>.
Then you could just say, “give me a Nix overlay corresponding to my build plan” and not have to go through the loop of building with Nix, observing the due to version bounds failure, then overriding the offending package.
Maybe this would be better as a separate tool, though.</p>
<h2 id="sage-fixes"><a href="#sage-fixes"><code>sage</code> fixes</a></h2>
<p><em>November</em></p>
<p><a href="https://github.com/LightAndLight/sage" class="uri">https://github.com/LightAndLight/sage</a></p>
<p><code>sage</code> is my fast, low-allocation parser combinator library.
It had a gnarly, almost non-determistic bug that I’d been aware of since my work on <a href="#diagnostica-and-diagnostica-sage-improvements"><code>diagnostica</code> and <code>diagnostica-sage</code> improvements</a>,
but for a long time I was stumped.
At my wit’s end, I decided to run the code through a large language model to see if I had missed anything.
The LLM suggested that there was a potential laziness issue where an <code>Addr#</code> was sticking around in a thunk and being garbage collected before the thunk was force.
This was indeed the problem, and I fixed the bug by changing a <code>$</code> to a <code>$!</code>.</p>
<h2 id="tsk"><a href="#tsk"><code>tsk</code></a></h2>
<p><em>October–December</em></p>
<ul>
<li><a href="https://github.com/LightAndLight/tsk" class="uri">https://github.com/LightAndLight/tsk</a></li>
<li><a href="https://tsk.ielliott.io/" class="uri">https://tsk.ielliott.io/</a></li>
</ul>
<p><code>tsk</code> is an attempt at local-first task tracking.
I used <a href="https://www.todoist.com/">Todoist</a> for a long time, sometimes paid and sometimes free.
In 2025 I decided that I didn’t want to use a software-as-a-service for something I could write myself.</p>
<p>The task “database” is a <a href="https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type">replicated datatype</a>,
which means that no matter how the database diverges due to edits on different devices,
the divergences can always be automatically reconciled.
Sometimes this results in “conflicts” when there are multiple competing values for a field.
The difference between <code>tsk</code> and something like Git is that the program doesn’t abort on merge conflicts;
now the conflicting field has more than one potential value.
As the user, you get to make a new edit that makes one of the candidate values canonical,
or you can overwrite it with something new.</p>
<p>The database is stored as a single binary file, whose format is documented <a href="https://tsk.ielliott.io/v0">here</a>.
That documentation is generated from the same code that encodes/decodes the binary format,
so it’s easier to keep the documentation in sync (I’m quite proud of this!).</p>
<p><code>tsk</code> uses the system’s editor and pager as its interface.
<code>tsk task new</code> opens <code>$EDITOR</code> with a “new task” template,
and after saving and exiting it parses the file, updates the database in memory, then overwrites the database on disk.
<code>tsk task edit ID</code> loads the database into memory, looks up the task, and then prints it to a temporary file that’s opened in the editor.
<code>tsk task view {ID}</code> does a similar thing but sends the printed task to <code>$PAGER</code> instead of an editor.
I think it’s cool to have a textual interface to a binary file; it feels like getting the best of both worlds.</p>
<p>The next big hurdle for this project is getting all of it to work on my smartphone.</p>
<h2 id="mdlink"><a href="#mdlink"><code>mdlink</code></a></h2>
<p><em>December</em></p>
<p><a href="https://github.com/LightAndLight/personal-configs/tree/533bc27168fc155b56ed055294b9feda06308733/system/packages/mdlink" class="uri">https://github.com/LightAndLight/personal-configs/tree/533bc27168fc155b56ed055294b9feda06308733/system/packages/mdlink</a></p>
<p><code>mdlink</code> is a script that turns URLs into Markdown-formatted links based on the pages <code>&lt;title&gt;</code>s.</p>
<p>e.g.</p>
<pre><code>https://kagi.com
https://zsa.io
https://blog.ielliott.io</code></pre>
<p>becomes</p>
<pre><code>[Kagi Search - A Premium Search Engine](https://kagi.com)
[The Voyager: A powerful, low-profile, split ergonomic keyboard | zsa.io](https://zsa.io)
[blog.ielliott.io](https://blog.ielliott.io)</code></pre>
<p>I use this script while writing in the <a href="https://helix-editor.com/">Helix editor</a>.
I select all the lines with URLs on them, type <code>|</code>, then <code>mdlink</code>, then <code>ENTER</code>.
Helix runs the script and replaces each line with the corresponding Markdown link.
Normally I only need to use this for a single link, though.</p>
<p>I used <a href="https://www.nushell.sh/">Nushell</a> to write <code>mdlink</code>.
I wanted inputs like <code>a\nb\n</code> to be equivalent to <code>a\nb</code> (a 2-item list), but I couldn’t find an elegant way to do that in Bash.
Bash wants the former to be a 3-item list and the latter to be a 2-item list.
Nushell on the other hand had a built in function that works the way I expected.</p>
<h2 id="syncthing-merge-and-asker"><a href="#syncthing-merge-and-asker"><code>syncthing-merge</code> and <code>asker</code></a></h2>
<p><em>December</em></p>
<ul>
<li><a href="https://github.com/LightAndLight/syncthing-merge" class="uri">https://github.com/LightAndLight/syncthing-merge</a></li>
<li><a href="https://github.com/LightAndLight/asker" class="uri">https://github.com/LightAndLight/asker</a></li>
<li><a href="https://github.com/LightAndLight/personal-configs/blob/533bc27168fc155b56ed055294b9feda06308733/system/sync.nix#L54-L94" class="uri">https://github.com/LightAndLight/personal-configs/blob/533bc27168fc155b56ed055294b9feda06308733/system/sync.nix#L54-L94</a></li>
</ul>
<p><code>syncthing-merge</code> is how I’m trying to bring my local-first task tracking to multiple computers.
Since <a href="#tsk"><code>tsk</code></a> uses a single file, I can easily sync that file with Syncthing.
Unfortunately Syncthing doesn’t help me merge conflicting versions of a file.</p>
<p><code>syncthing-merge</code> is a daemon that uses <a href="https://docs.syncthing.net/dev/events.html">Syncthing’s Events API</a> to monitor for conflicts and then run a resolution script.
So when Syncthing creates sync conflicts on a <code>tsk</code> database, <code>syncthing-merge</code> will run <code>tsk merge</code> and then clean up.</p>
<p>I also use Syncthing to sync my KeepassXC database, but <code>keepassxc-cli merge</code> requires my primary password to unlock the databases.
I built <code>asker</code> to allow the <code>syncthing-merge</code> daemon securely request this password while preventing other programs from doing the same.
It would have been good to use existing keyring solutions but I couldn’t figure out how to get the level of access control that I wanted
(see <a href="https://github.com/LightAndLight/asker?tab=readme-ov-file#prior-art">“prior art” in the README</a> for a longer explanation).</p>
<h2 id="rand"><a href="#rand"><code>rand</code></a></h2>
<p><em>December</em></p>
<p><a href="https://github.com/LightAndLight/rand" class="uri">https://github.com/LightAndLight/rand</a></p>
<p><code>rand</code> is a command-line program for generating random strings.
Here’s an example run:</p>
<pre><code>$ rand 64 hex
d88bb57566ab8d8b279b51767d2f747c937320cbf98cd08c657a7d23b3c17216</code></pre>
<p>I used it to generate the API key that <code>syncthing-merge</code> uses to authenticate against Syncthing.</p>
<p>A fun variation on this would be to provide a regular expression instead of a digit identifier like “hex”,
and generate a random string that matches the regex.
Let’s call it <code>genreg</code> for “GENerate REGex”:</p>
<pre><code>$ genreg &#39;[0-9a-f]{64}&#39;
d88bb57566ab8d8b279b51767d2f747c937320cbf98cd08c657a7d23b3c17216

$ genreg &#39;hello|goodbye&#39;
hello

$ genreg &#39;hello|goodbye&#39;
goodbye</code></pre>
    ]]></content>
    
</entry>
<entry>
    <title>Removing Disqus</title>
    <link href="https://blog.ielliott.io/removing-disqus" />
    
    <id>https://blog.ielliott.io/removing-disqus</id>
    
    <published>2025-09-24T00:00:00Z</published>
    <updated>2025-09-24T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/removing-disqus"><![CDATA[<p><a href="https://disqus.com/">Disqus</a> recently sent me an email, warning that (thank you) they will soon enable ads in my site’s comment sections (no thank you).</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/removing-disqus"><![CDATA[
      
      <p><a href="https://disqus.com/">Disqus</a> recently sent me an email, warning that (thank you) they will soon enable ads in my site’s comment sections (no thank you).</p>
<p>Comments are going away for now, because I’m not going to pay for ad-free Disqus.
You can still get in touch via email (see the site footer).</p>
<p>I’ve also exported all the comments from Disqus so that I can restore them if I ever build a comment system.</p>
<p>Disqus hosted this site’s comments for 10 years, and I never paid them a cent.
I wonder how many other people did this too?
It seems like a bad business strategy; the free version was good enough, so why would anyone pay for it?
They’d inevitably have to stop giving out free lunches.</p>
<p>But suppose it weren’t a bad strategy,
because somehow the freeloading blogs were indirectly helpful in achieving profitability.
What does that say about Disqus’ current direction?
Their profit might be decreasing, meaning that paying users are no longer enough to subsidise the freeloaders.
But if their profit is <em>not</em> decreasing, then they’re being greedy and trying to extract more from their current users.</p>
    ]]></content>
    
</entry>
<entry>
    <title>Smalltalk and Lambda Calculus</title>
    <link href="https://blog.ielliott.io/smalltalk-and-lambda-calculus" />
    
    <id>https://blog.ielliott.io/smalltalk-and-lambda-calculus</id>
    
    <published>2025-09-13T00:00:00Z</published>
    <updated>2025-09-13T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/smalltalk-and-lambda-calculus"><![CDATA[<p>In <a href="https://en.wikipedia.org/wiki/Smalltalk">Smalltalk</a>, everything is an “object”.
An “object” is a thing that receives and processes “messages”.
A “message” has a name and zero or more arguments.
How do you build express common datatypes, such as booleans and numbers, using only objects?</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/smalltalk-and-lambda-calculus"><![CDATA[
      
      <div id="toc">
<h3>Contents</h3>
<ul>
<li><a href="#boolean-objects">Boolean objects</a></li>
<li><a href="#natural-number-objects">(Natural) number objects</a></li>
<li><a href="#lambda-calculus">Lambda calculus</a></li>
<li><a href="#objects--lambas">Objects ↔︎ lambas</a></li>
<li><a href="#thoughts">Thoughts</a></li>
</ul>
</div>
<p>In <a href="https://en.wikipedia.org/wiki/Smalltalk">Smalltalk</a>, everything is an “object”.
An “object” is a thing that receives and processes “messages”.
A “message” has a name and zero or more arguments.
How do you build express common datatypes, such as booleans and numbers, using only objects?</p>
<h2 id="boolean-objects"><a href="#boolean-objects">Boolean objects</a></h2>
<p>A Smalltalk boolean is an object that understands a message named <code>ifTrue:ifFalse:</code>.
<code>ifTrue:ifFalse:</code> takes two arguments, which should both be <a href="https://en.wikipedia.org/wiki/Smalltalk#Code_blocks">“code blocks”</a>.
<code>true</code> is the boolean that, when it receives <code>ifTrue: firstArgument ifFalse: secondArgument</code>, runs <code>firstArgument</code>.
On the other hand, <code>false</code> is the boolean that runs <code>secondArgument</code>.
This can be concisely specified by two equations:</p>
<ol type="1">
<li><code>true ifTrue: a ifFalse b = a value</code></li>
<li><code>false ifTrue: a ifFalse: b = b value</code></li>
</ol>
<h2 id="natural-number-objects"><a href="#natural-number-objects">(Natural) number objects</a></h2>
<p>What about numbers?
The introductions to Smalltalk that I’ve skimmed don’t talk about constructing numbers.
One message to integers stands out, though: <code>timesRepeat:</code>.
<code>timesRepeat:</code> takes one argument, a code block.
An integer object <code>n</code> processes <code>timesRepeat:</code> by running the code block <code>n</code> times (and zero times if the integer is negative).
The caveat for negative integers suggests that <code>timesRepeat:</code> is better suited for natural numbers, but Smalltalk doesn’t have them in its numeric hierarchy.</p>
<p><code>timesRepeat:</code> almost characterises natural numbers, but not quite.
Here’s my characterisation.
A natural number is an object that understands a message named <code>from:iterate:</code> (I made this up so I don’t know if there’s a standard Smalltalk equivalent).
The message takes two arguments, an arbitrary object and a single-argument code block.
<code>0</code> is the natural number that, when it receives <code>from: initial iterate: next</code>, just returns <code>initial</code>.
A natural number <code>n</code> (where <code>n &gt; 0</code>) is an object that contains a reference to its predecessor (called <code>pred</code>).
<code>from: initial iterate: next</code> is implemented as follows:</p>
<pre class="smalltalk"><code>from: initial iterate: next [
  ^next value: (pred from: initial iterate: next)
]</code></pre>
<p><code>timesRepeat:</code> can be implemented in terms of <code>from:iterate:</code>:</p>
<pre class="smalltalk"><code>timesRepeat: block [
  from: nil iterate: [ :ignored | block value ]
]</code></pre>
<p>The specification is:</p>
<ol type="1">
<li><code>0 from: initial iterate: next = initial</code></li>
<li><code>n succ from: initial iterate: next = n from: (next value: initial) iterate: next</code></li>
</ol>
<h2 id="lambda-calculus"><a href="#lambda-calculus">Lambda calculus</a></h2>
<p>Where objects are the fundamental building blocks of Smalltalk, (single-argument) functions are the fundamental building blocks of <a href="https://en.wikipedia.org/wiki/Lambda_calculus">lambda calculus</a>.
Datatypes like booleans and (natural) numbers can also be expressed using only functions.</p>
<p>A boolean is a function that takes two arguments; the <code>true</code> boolean chooses the first argument and the <code>false</code> boolean chooses the second:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>true <span class="ot">=</span> \x y <span class="ot">-&gt;</span> x</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>false <span class="ot">=</span> \x y <span class="ot">-&gt;</span> y</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>ifTrueIfFalse cond x y <span class="ot">=</span> cond x y</span></code></pre></div>
<p>A natural number <code>n</code> is a function that takes two arguments, and applies the second argument to the first <code>n</code> times:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>zero <span class="ot">=</span> \x f <span class="ot">-&gt;</span> x</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="fu">succ</span> n <span class="ot">=</span> \x f <span class="ot">-&gt;</span> f (n x f)</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>fromIterate n x f <span class="ot">=</span> n x f</span></code></pre></div>
<p>These definitions (known as <a href="https://en.wikipedia.org/wiki/Church_encoding">Church encodings</a>) express exactly the same intent as the Smalltalk equivalents.
This is not a coincidence: Smalltalk’s objects and lambda calculus’ functions are actually the same sort of thing.</p>
<h2 id="objects--lambas"><a href="#objects--lambas">Objects ↔︎ lambas</a></h2>
<p>A lambda is an object that understands a single-argument message called <code>value:</code>.
The object responds to the <code>value:</code> message by transforming the argument and returning a result.</p>
<p>An object is a lambda that takes two arguments: a message name, and the message payload.
When then lambda is applied to a message name and payload, it uses the message name to look up a handler function and applies that function to the payload.</p>
<p>Variables captured by the lambda are the object’s instance variables, and vice versa.
In both cases, these variables aren’t detectable from the outside.</p>
<p>While I haven’t mentioned types thus far, in the end type theory explains the connection between objects and lambdas:
they’re both <a href="https://en.wikipedia.org/wiki/Coinduction">coinductive types</a> (see also: <a href="https://blog.ielliott.io/lambdas-are-codatatypes">Lambdas are Codatatypes</a>).</p>
<h2 id="thoughts"><a href="#thoughts">Thoughts</a></h2>
<ul>
<li><p>In general, Smalltalk feels like a nicer syntax for church encoding. I like it.</p></li>
<li><p>I wonder why Smalltalk doesn’t have anonymous objects?</p>
<p>The language already has a small conceptual footprint, but because objects can only be created by messaging a class (which is itself an object),
classes and objects need to be defined in terms of each other.
Maybe classless, anonymous objects could serve as the foundation for a classy object system.</p></li>
</ul>
    ]]></content>
    
</entry>
<entry>
    <title>A Haskell "Foldable" quiz</title>
    <link href="https://blog.ielliott.io/haskell-foldable-quiz" />
    
    <id>https://blog.ielliott.io/haskell-foldable-quiz</id>
    
    <published>2025-08-21T00:00:00Z</published>
    <updated>2025-08-21T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/haskell-foldable-quiz"><![CDATA[<p>How does GHCi respond to <code>fold [] 42</code>?</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/haskell-foldable-quiz"><![CDATA[
      
      <p>How does GHCi respond to <code>fold [] 42</code>?</p>
<details>
<summary>
Answer
</summary>
<pre><code>ghci&gt; fold [] 42
()</code></pre>
</details>
<p>How does GHCi respond to <code>fold [] 42 == []</code>?</p>
<details>
<summary>
Answer
</summary>
<pre><code>ghci&gt; fold [] 42 == []
True</code></pre>
</details>
<p>What is the type of <code>fold [] 42</code>?</p>
<details>
<summary>
Answer
</summary>
<pre><code>ghci&gt; :t fold [] 42
fold [] 42 :: Monoid t =&gt; t</code></pre>
</details>
<p>What the hell is going on!?</p>
<details>
<summary>
Answer
</summary>
<p><code>fold</code> has type <code>(Foldable t, Monoid a) =&gt; t a -&gt; a</code>, so <code>fold []</code> has type <code>Monoid a =&gt; a</code>.</p>
<p><code>fold []</code> is <code>mempty</code>, which means <code>fold [] 42</code> is equal to <code>mempty 42</code>.
This is well-typed because <em>functions</em> have a Monoid instance.</p>
<p><code>mempty</code> for functions is <code>const mempty</code>.
So <code>mempty 42</code> is <code>const mempty 42</code> is <code>mempty :: Monoid b =&gt; b</code>.</p>
<p>In GHCi, <code>b</code> is defaulted to <code>()</code>, which is why the first question prints <code>()</code>.</p>
When we evaluate <code>fold [] 42 == []</code>, the list monoid is chosen instead, reducing to <code>[] == []</code>.
</details>
<p>Why am I even thinking about this?</p>
<details>
<summary>
Answer
</summary>
<p>I just found a bug due to replacing <code>fromMaybe Set.empty</code> (which has type <code>Maybe (Set a) -&gt; Set a</code>) with <code>fold Set.empty</code> (which has type <code>Monoid b =&gt; a -&gt; b</code> and is equivalent to <code>const mempty</code>).
This meant that all my <code>Just</code>s containing non-empty sets were being ignored.</p>
I meant to replace <code>fromMaybe Set.empty</code> with <code>fold</code>, which really are the same.
</details>
    ]]></content>
    
</entry>
<entry>
    <title>Paying for KeePassXC</title>
    <link href="https://blog.ielliott.io/paying-for-keepassxc" />
    
    <id>https://blog.ielliott.io/paying-for-keepassxc</id>
    
    <published>2025-08-17T04:25:00Z</published>
    <updated>2025-08-17T04:25:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/paying-for-keepassxc"><![CDATA[<p><a href="https://keepassxc.org/">KeePassXC</a> is a password management program.
I’ve been using it since January, when <a href="https://en.wikipedia.org/wiki/LastPass">LastPass</a> randomly stopped working on Firefox.
I realised that something was wrong when
<a href="https://www.theverge.com/2022/12/22/23523322/lastpass-data-breach-cloud-encrypted-password-vault-hackers">LastPass was hacked in late 2022</a>,
and it took two years for LastPass to become noticeably crap enough
(partly due to software changes, and partly due to evolution of my software ethics)
for me to switch.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/paying-for-keepassxc"><![CDATA[
      
      <p><a href="https://keepassxc.org/">KeePassXC</a> is a password management program.
I’ve been using it since January, when <a href="https://en.wikipedia.org/wiki/LastPass">LastPass</a> randomly stopped working on Firefox.
I realised that something was wrong when
<a href="https://www.theverge.com/2022/12/22/23523322/lastpass-data-breach-cloud-encrypted-password-vault-hackers">LastPass was hacked in late 2022</a>,
and it took two years for LastPass to become noticeably crap enough
(partly due to software changes, and partly due to evolution of my software ethics)
for me to switch.</p>
<figure>
<img src="/images/20250817-keepassxc-screenshot.png">
<figcaption>
Screenshot of my KeePassXC database (sensitive details redacted)
</figcaption>
</figure>
<p>After 8 months of use, I’m glad to say that I have no complaints.
KeePassXC does precisely what it’s supposed to do.</p>
<p>The program doesn’t use the internet,
which means I don’t have to worry about sudden and irreversable enshittification
(e.g. through automatic updates) or cancellation (e.g. shutdown of a critical proprietary service).
Because it’s <a href="https://github.com/keepassxreboot/keepassxc">open source</a>,
if the developers <em>do</em> take the software in a disagreeable direction then I can continue to use a version I like.
If the software doesn’t quite work properly for me,
then I can create my own <a href="https://github.com/LightAndLight/personal-configs/blob/main/patches/keepassxc/allow-read-only-native-message-files.patch">modified version</a>
and <a href="https://github.com/keepassxreboot/keepassxc/pull/12236">share my changes with the project</a>.</p>
<p>Part of the problem with the modern software industry is the business incentive to build scarcity into the digital medium.
When I buy a material good from you, I give you money in exchange for possession of the item.
I physically take the item away from you, and you’re left with the money I gave you.
Software doesn’t work like this: when I buy software from you, I give you money in exchange for <em>a copy</em> of the software.
Now we <em>both</em> possess the software (see also: <a href="https://web.archive.org/web/19961128031345/https://www.wired.com/wired/2.03/features/economy.ideas.html">“The Economy of Ideas” by John Perry Barlow</a>).
Now I can transmit my copy to someone else without them or me paying you, and so on.
Businesses invent increasingly invasive and disempowering ways
to capture as much of the value as possible that their software creates
(e.g. <a href="https://en.wikipedia.org/wiki/Digital_rights_management">DRM</a>, <a href="https://en.wikipedia.org/wiki/Software_as_a_service">SaaS</a>).</p>
<p>KeePassXC has none of these artificial restrictions.
We normally describe such software as “free”, as in, “you can legally obtain copies of this software without giving anything in exchange”.
But until we can come up with a better economic system, I think it’s important to pay for good software, especially if it isn’t held for ransom.
And until we have a better understanding of the economy of ideas,
I’ll still talk about “buying” software as one would buy a material good.
So how much should I pay for KeePassXC?</p>
<p>One reference point I have is the price of a cup of coffee, which around here is ~5AUD.
I’m fortunate enough to be able to regularly buy coffee without concern for the price.
If I bought a 5AUD coffee on 200 out of 365 days (a <em>very</em> conservative lower bound ☕☕☕),
I would have spent 1000AUD on coffee in a single year.
Since I’m willing to spend that amount on a drink,
how much should I be willing to pay for a solid piece of software like KeePassXC,
which I can use as much as I want without exhausting my supply?
Honestly, my first reaction is that I should buy less coffee.
That aside, KeePassXC is obviously worth more than a single coffee, because I can use it more than once (but I can only drink a particular coffee once).
But it’s not worth 10,000 coffees because I could build it myself for less.</p>
<p>What about 100 coffees?
That’s ~500AUD, which is only of what I might actually spend on coffee in a <em>single year</em>.
Break it down as 100AUD or 20 coffees per year over 5 years (I’m very confident that I can use KeePassXC for 5+ years due to its anti-enshittification protections).
That’s not a bad deal for a program as useful and reliable as KeePassXC, although for some reason it still feels a little steep.</p>
<p>In the end, the final number is not too important to me.
I suspect there are too many ways that humans can be inconsistent when assigning numeric values to things.
The main point is that the final number is <em>not zero</em>, because this software really is valuable.</p>
<p>You can buy KeePassXC <a href="https://keepassxc.org/donate/">here</a>.</p>
    ]]></content>
    
</entry>
<entry>
    <title>Note: "We just experienced a tiny earthquake!"</title>
    <link href="https://blog.ielliott.io/note/202508160025" />
    
    <id>https://blog.ielliott.io/note/202508160025</id>
    
    <published>2025-08-16T00:25:00Z</published>
    <updated>2025-08-16T00:25:00Z</updated>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/note/202508160025"><![CDATA[
      
      
      <hr>
      
      <p>We just experienced a tiny earthquake!</p>
<p>You can see it <a href="https://stationview.raspberryshake.org/#/?lat=-26.92656&amp;lon=153.21995&amp;zoom=9.060&amp;event=rs2025qarmsa">on the Raspberry Shake network</a>,
which I recently read about in <a href="https://interconnected.org/home/2025/08/01/filtered">Filtered for bottom-up global monitoring (Interconnected)</a>.
The Raspberry Shake network reports a magnitude 4.9 earthquake at 2025-08-15 23:49:24 UTC with an epicentre of 26.5° S 152.1° E,
roughly 100km west of the Sunshine Coast.</p>
<figure>
<a target="_blank" href="/images/20250816-raspberry-shake-screenshot.png">
<img src="/images/20250816-raspberry-shake-screenshot-small.png">
</a>
<figcaption>
Screenshot of the earthquake’s entry on <a href="https://stationview.raspberryshake.org">stationview.raspberryshake.org</a>
</figcaption>
</figure>
<p>I’m in Brisbane, which is about 140km away from the epicentre.
The house shook a little bit as if a really strong wind was blowing, but there was no wind outside.</p>
    ]]></content>
    
</entry>
<entry>
    <title>Reply to "Standalone relational storage engines?"</title>
    <link href="https://blog.ielliott.io/reply/202508052146" />
    
    <id>https://blog.ielliott.io/reply/202508052146</id>
    
    <published>2025-08-05T21:46:00Z</published>
    <updated>2025-08-05T21:46:00Z</updated>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/reply/202508052146"><![CDATA[
      
      
      <p>Reply to <a href="/exploring-graphs-with-prolog#standalone-relational-storage-engines">Standalone relational storage engines?</a></p>
      
      <hr>
      
      <p><a href="https://vaibhavsagar.com/">Vaibhav</a> offered <a href="https://en.wikipedia.org/wiki/RocksDB">RocksDB</a> and <a href="https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database">LMDB</a>
as candidates for “ZeroMQ for database storage”.</p>
<p>Facebook has <a href="https://en.wikipedia.org/wiki/MyRocks">a MySQL storage backend that uses RocksDB</a>,
and LMDB has been used as a storage backend for <a href="https://github.com/LMDB/sqlightning">(a fork of) SQLite</a>.</p>
<p>I was surprised, because these databases describe themselves as key-value stores,
which doesn’t seem like the right data structure for relational queries.
I had missed the fact that these are <a href="https://en.wikipedia.org/wiki/Ordered_key%E2%80%93value_store"><em>ordered</em> key-value stores</a>,
so they support range queries.</p>
    ]]></content>
    
</entry>
<entry>
    <title>Exploring a dependency graph with Prolog</title>
    <link href="https://blog.ielliott.io/exploring-graphs-with-prolog" />
    
    <id>https://blog.ielliott.io/exploring-graphs-with-prolog</id>
    
    <published>2025-08-02T07:00:00Z</published>
    <updated>2025-08-02T07:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/exploring-graphs-with-prolog"><![CDATA[<p>I was working on my (currently private) <a href="https://lectio.news/">YouTube feed reader project</a>,
watching the dependencies build after I upgraded the GHC version,
when I noticed an odd transitive dependency: <a href="https://hackage.haskell.org/package/happy"><code>happy</code></a>.
<code>happy</code> is a parser generator, and this project is a web app.
Why does my web app depend on a parser generator?</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/exploring-graphs-with-prolog"><![CDATA[
      
      <div id="toc">
<h3>Contents</h3>
<ul>
<li><a href="#setup">Setup</a></li>
<li><a href="#exploration">Exploration</a></li>
<li><a href="#thoughts-and-ideas">Thoughts and ideas</a></li>
</ul>
</div>
<p>I was working on my (currently private) <a href="https://lectio.news/">YouTube feed reader project</a>,
watching the dependencies build after I upgraded the GHC version,
when I noticed an odd transitive dependency: <a href="https://hackage.haskell.org/package/happy"><code>happy</code></a>.
<code>happy</code> is a parser generator, and this project is a web app.
Why does my web app depend on a parser generator?</p>
<p>This reminded me of my recent <a href="https://blog.ielliott.io/playing-with-ghc-package-databases">Haskell dependency graph exploration</a>,
where I wondered whether there was a good way to query dependency graph.
It then occurred to me that <a href="https://en.wikipedia.org/wiki/Datalog">Datalog</a> might be a good query language for this.
I couldn’t find a canonical FOSS Datalog implementation, so I went with <a href="https://www.gprolog.org/">GNU Prolog</a> instead.
Here’s how it turned out.</p>
<h2 id="setup"><a href="#setup">Setup</a></h2>
<p>We’re going to turn the output of <code>ghc-pkg dot</code> into a set of Prolog facts.
An edge from <code>a</code> to <code>b</code> will be encoded as a fact <code>depends_on(a, b)</code>.</p>
<details class="shell-command" open>
<summary>
<samp>$ <kbd>cat &gt; dot2pl.py &lt;&lt;EOF</kbd></samp>
</summary>
<pre><samp>$ <kbd>cat > dot2pl.py &lt;&lt;EOF
import re
import sys

def dot_to_prolog(dot_content):
    edges = re.findall(r'"(.+)"\s*->\s*"(.+)"', dot_content)

    for source, target in edges:
        print(f"depends_on('{source}', '{target}').")

line = input()
if line == "digraph {":
    pass
else:
    raise Error(f"Expected {"digraph {"}, got {line}")

while True:
    line = input()
    if line == "}":
        break
    else:
        dot_to_prolog(line)
EOF
</kbd></samp></pre>
</details>
<details>
<summary>
(no output)
</summary>
</details>
<p>Where are my package databases?</p>
<samp>$ <kbd>cabal exec -- bash c 'cat $(printenv GHC_ENVIRONMENT) | head -n 20'</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>
Configuration is affected by the following files:
- cabal.project
-- This is a GHC environment file written by cabal. This means you can
-- run ghc or ghci and get the environment of the project as a whole.
-- But you still need to use cabal repl $target to get the environment
-- of specific components (libs, exes, tests etc) because each one can
-- have its own source dirs, cpp flags etc.
--
clear-package-db
global-package-db
package-db /home/isaac/.local/state/cabal/store/ghc-9.8.4-4a67/package.db
package-db /home/isaac/youtube-feeds/dist-newstyle/packagedb/ghc-9.8.4
package-id youtube-feeds-atom-0.1.0.0-inplace
package-id base-4.19.2.0-32b8
package-id ghc-bignum-1.3-455a
package-id ghc-prim-0.11.0-3f63
package-id rts-1.0.2
package-id bytestring-0.12.1.0-2a7c
package-id deepseq-1.5.1.0-88f5
package-id template-haskell-2.21.0.0-bbd9
package-id ghc-boot-th-9.8.4-77b2
package-id pretty-1.1.3.6-6e96
</samp></pre>
</details>
<p>Generate the facts.</p>
<samp>$ <kbd>ghc-pkg --package-db=/home/isaac/.local/state/cabal/store/ghc-9.8.4-4a67/package.db --package-db=/home/isaac/youtube-feeds/dist-newstyle/packagedb/ghc-9.8.4 dot | python3 dot2pl.py &gt; deps.pl</kbd></samp>
<details>
<summary>
(no output)
</summary>
</details>
<p>Now add some definitions for graph manipulation.</p>
<p class="contains-snippet">
<code>why_depends</code> is named after <a href="https://nix.dev/manual/nix/2.26/command-ref/new-cli/nix3-why-depends"><code>nix why-depends</code></a>,
which is the canonical way to ask this question of installed Nix derivations.
<a class="snippet" id="why-depends-inspiration" href="#why-depends-inspiration">Part of my inspiration for this investigation is the sense that a question like <code>why-depends</code> shouldn’t be baked into CLI of a tool like Nix.
Instead, there should be a language in which it’s easy to ask that question and all the other questions that would never have been anticipated by the tool’s authors.</a>
<a class="snippet-anchor" href="#why-depends-inspiration">#</a>
</p>
<details class="shell-command" open>
<summary>
<samp>$ <kbd>cat &gt; graph.pl &lt;&lt;EOF</kbd></samp>
</summary>
<pre><samp>$ <kbd>cat > graph.pl &lt;&lt;EOF
% Identify nodes.
node(X) :- depends_on(X, _).

% Identify paths from one node to another.
why_depends(X, Y, [X, Y]) :- depends_on(X, Y).
why_depends(X, Z, [X, Y | P]) :- depends_on(X, Y), why_depends(Y, Z, [Y | P]).
EOF
</kbd></samp></pre>
</details>
<details>
<summary>
(no output)
</summary>
</details>
<h2 id="exploration"><a href="#exploration">Exploration</a></h2>
<samp>$ <kbd>gprolog</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>GNU Prolog 1.5.0 (64 bits)
Compiled Jul  8 2021, 09:35:47 with gcc
Copyright (C) 1999-2025 Daniel Diaz

| ?-
</samp></pre>
</details>
<samp>| ?- <kbd>[deps]. [graph].</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>
compiling /home/isaac/youtube-feeds/deps.pl for byte code...
/home/isaac/youtube-feeds/deps.pl compiled, 335 lines read - 53725 bytes written, 8 ms

(2 ms) yes
compiling /home/isaac/youtube-feeds/graph.pl for byte code...
/home/isaac/youtube-feeds/graph.pl compiled, 4 lines read - 993 bytes written, 2 ms

yes
</samp></pre>
</details>
<p>What dependencies do we have?</p>
<samp>| ?- <kbd>setof(N, node(N), Ns).</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>
Ns = ['MemoTrie-0.6.11','QuickCheck-2.15.0.1','aeson-2.2.3.0','ansi-terminal-1.1.2','ansi-terminal-types-1.1','asn1-encoding-0.9.6','asn1-parse-0.9.5','asn1-types-0.3.4','async-2.2.5','attoparsec-0.14.4','base64-1.0','bifunctors-5.6.2','blaze-textual-0.2.3.1','case-insensitive-1.2.1.0','cborg-0.2.10.0','comonad-5.0.9','contravariant-1.5.5','cookie-0.5.0','crypton-1.0.1','crypton-connection-0.4.3','crypton-x509-1.7.7','crypton-x509-store-1.6.9','crypton-x509-system-1.6.7','crypton-x509-validation-1.6.13','data-default-class-0.2.0.0','data-fix-0.3.4','distributive-0.6.2.1','generics-sop-0.5.1.4','graphviz-2999.20.2.0','happy-lib-2.1.3','hashable-1.5.0.0','http-client-0.7.18','http-client-tls-0.3.6.4','http-date-0.0.11','http-media-0.8.1.1','http-semantics-0.3.0','http-types-0.12.4','http2-5.3.9','indexed-traversable-instances-0.1.2','integer-conversion-0.1.1','iproute-1.7.15','memory-0.18.0','network-control-0.1.3','network-uri-2.6.4.2','old-time-1.1.0.4','pem-0.2.4','pretty-show-1.10','prettyprinter-ansi-terminal-1.1.3','psqueues-0.2.8.0','quickcheck-state-machine-0.10.1','random-1.2.1.3','recv-0.1.0','scientific-0.3.8.0','semialign-1.3.1','semigroupoids-6.0.1','serialise-0.2.6.1','simple-sendfile-0.2.32','socks-0.6.1','sqlite-simple-0.4.19.0','streaming-commons-0.2.2.6','strict-0.5.1','temporary-1.3','text-iso8601-0.1.1','text-short-0.1.6','these-1.2.1','time-compat-1.9.8','time-manager-0.2.2','tls-2.1.6','unix-time-0.4.16','unliftio-0.2.25.0','unordered-containers-0.2.20','uri-encode-1.5.0.7','uuid-types-1.0.6','vault-0.3.1.5','vector-0.13.2.0','wai-3.2.4','warp-3.4.7','witherable-0.5','wl-pprint-text-1.2.0.2','youtube-feeds-log-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','youtube-feeds-server-0.1.0.0','youtube-feeds-sql-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0','z-happy-lib-z-backend-glr-2.1.3','z-happy-lib-z-backend-lalr-2.1.3','z-happy-lib-z-frontend-2.1.3','z-happy-lib-z-tabular-2.1.3','z-quickcheck-state-machine-z-no-vendored-treediff-0.10.1']

yes
</samp></pre>
</details>
<p>Looks good.</p>
<p>I can’t find <code>happy</code> in there at a glance.
Is <code>happy</code> in here?</p>
<samp>| ?- <kbd>setof(N, (node(N), atom_concat(happy, _, N)), Ns).</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>
Ns = ['happy-lib-2.1.3']

yes
</samp></pre>
</details>
<p>Cool. What are the names of my project’s packages again?</p>
<samp>| ?- <kbd>setof(N, Suffix^(node(N), atom_concat('youtube-feeds', Suffix, N)), Ns).</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>
Ns = ['youtube-feeds-log-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','youtube-feeds-server-0.1.0.0','youtube-feeds-sql-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0']

yes
</samp></pre>
</details>
<p>Let’s see whether the first one depends on <code>happy</code>.</p>
<samp>| ?- <kbd>why_depends('youtube-feeds-log-0.1.0.0', 'happy-lib-2.1.3', Path).</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>
no
</samp></pre>
</details>
<p>It doesn’t. Let’s check them all.</p>
<samp>| ?- <kbd>setof(N, Suffix^(node(N), atom_concat('youtube-feeds', Suffix, N)), Ns), member(Package, Ns), why_depends(Package, 'happy-lib-2.1.3', Path).</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>
no
</samp></pre>
</details>
<p>Okay, that’s surprising. I definitely saw <code>happy</code> being built.</p>
<p>Well, what depends on <code>happy-lib-2.1.3</code>?</p>
<samp>| ?- <kbd>setof(P, depends_on(P, 'happy-lib-2.1.3'), Ps).</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>
no
</samp></pre>
</details>
<p>Hm. Okay, I think that <code>happy</code> is an <em>executable</em> required for the build of another package.</p>
<p>Since that didn’t work out, let’s play with this approach by looking for the ways I depend on <code>cborg-0.2.10.0</code>.</p>
<samp>| ?- <kbd>setof(N, Suffix^(node(N), atom_concat('youtube-feeds', Suffix, N)), Ns), member(Package, Ns), why_depends(Package, 'cborg-0.2.10.0', Path).</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>
Ns = ['youtube-feeds-log-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','youtube-feeds-server-0.1.0.0','youtube-feeds-sql-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0']
Package = 'youtube-feeds-oauth2-0.1.0.0'
Path = ['youtube-feeds-oauth2-0.1.0.0','http-client-tls-0.3.6.4','crypton-connection-0.4.3','tls-2.1.6','serialise-0.2.6.1','cborg-0.2.10.0'] ? ;

Ns = ['youtube-feeds-log-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','youtube-feeds-server-0.1.0.0','youtube-feeds-sql-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0']
Package = 'youtube-feeds-oauth2-0.1.0.0'
Path = ['youtube-feeds-oauth2-0.1.0.0','http-client-tls-0.3.6.4','tls-2.1.6','serialise-0.2.6.1','cborg-0.2.10.0'] ? ;

Ns = ['youtube-feeds-log-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','youtube-feeds-server-0.1.0.0','youtube-feeds-sql-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0']
Package = 'youtube-feeds-server-0.1.0.0'
Path = ['youtube-feeds-server-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','http-client-tls-0.3.6.4','crypton-connection-0.4.3','tls-2.1.6','serialise-0.2.6.1','cborg-0.2.10.0'] ? ;

Ns = ['youtube-feeds-log-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','youtube-feeds-server-0.1.0.0','youtube-feeds-sql-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0']
Package = 'youtube-feeds-server-0.1.0.0'
Path = ['youtube-feeds-server-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','http-client-tls-0.3.6.4','tls-2.1.6','serialise-0.2.6.1','cborg-0.2.10.0'] ? ;

Ns = ['youtube-feeds-log-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','youtube-feeds-server-0.1.0.0','youtube-feeds-sql-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0']
Package = 'youtube-feeds-server-0.1.0.0'
Path = ['youtube-feeds-server-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0','http-client-tls-0.3.6.4','crypton-connection-0.4.3','tls-2.1.6','serialise-0.2.6.1','cborg-0.2.10.0'] ? ;

Ns = ['youtube-feeds-log-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','youtube-feeds-server-0.1.0.0','youtube-feeds-sql-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0']
Package = 'youtube-feeds-server-0.1.0.0'
Path = ['youtube-feeds-server-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0','http-client-tls-0.3.6.4','tls-2.1.6','serialise-0.2.6.1','cborg-0.2.10.0'] ? ;

Ns = ['youtube-feeds-log-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','youtube-feeds-server-0.1.0.0','youtube-feeds-sql-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0']
Package = 'youtube-feeds-server-0.1.0.0'
Path = ['youtube-feeds-server-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','http-client-tls-0.3.6.4','crypton-connection-0.4.3','tls-2.1.6','serialise-0.2.6.1','cborg-0.2.10.0'] ? ;

Ns = ['youtube-feeds-log-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','youtube-feeds-server-0.1.0.0','youtube-feeds-sql-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0']
Package = 'youtube-feeds-server-0.1.0.0'
Path = ['youtube-feeds-server-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','http-client-tls-0.3.6.4','tls-2.1.6','serialise-0.2.6.1','cborg-0.2.10.0'] ? ;

Ns = ['youtube-feeds-log-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','youtube-feeds-server-0.1.0.0','youtube-feeds-sql-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0']
Package = 'youtube-feeds-youtubev3-api-0.1.0.0'
Path = ['youtube-feeds-youtubev3-api-0.1.0.0','http-client-tls-0.3.6.4','crypton-connection-0.4.3','tls-2.1.6','serialise-0.2.6.1','cborg-0.2.10.0'] ? ;

Ns = ['youtube-feeds-log-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','youtube-feeds-server-0.1.0.0','youtube-feeds-sql-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0']
Package = 'youtube-feeds-youtubev3-api-0.1.0.0'
Path = ['youtube-feeds-youtubev3-api-0.1.0.0','http-client-tls-0.3.6.4','tls-2.1.6','serialise-0.2.6.1','cborg-0.2.10.0'] ? ;

Ns = ['youtube-feeds-log-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','youtube-feeds-server-0.1.0.0','youtube-feeds-sql-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0']
Package = 'youtube-feeds-youtubev3-api-0.1.0.0'
Path = ['youtube-feeds-youtubev3-api-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','http-client-tls-0.3.6.4','crypton-connection-0.4.3','tls-2.1.6','serialise-0.2.6.1','cborg-0.2.10.0'] ? ;

Ns = ['youtube-feeds-log-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','youtube-feeds-server-0.1.0.0','youtube-feeds-sql-0.1.0.0','youtube-feeds-youtubev3-api-0.1.0.0']
Package = 'youtube-feeds-youtubev3-api-0.1.0.0'
Path = ['youtube-feeds-youtubev3-api-0.1.0.0','youtube-feeds-oauth2-0.1.0.0','http-client-tls-0.3.6.4','tls-2.1.6','serialise-0.2.6.1','cborg-0.2.10.0'] ? ;

(2 ms) no
</samp></pre>
</details>
<p>There’s a lot of duplication because some of the project’s packages depend on each other.
I think a better way to ask this question is to get all the project’s direct dependencies that transitively depend on the target.</p>
<samp>| ?- <kbd>assertz((project_packages(X) :- setof(N, Suffix^(node(N), atom_concat('youtube-feeds', Suffix, N)), X))).</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>
yes
</samp></pre>
</details>
<samp>| ?- <kbd>findall(Path, (project_packages(Packages), member(Package, Packages), depends_on(Package, Dep), \+ member(Dep, Packages), why_depends(Dep, 'cborg-0.2.10.0', Path)), Results).</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>
Results = [['http-client-tls-0.3.6.4','crypton-connection-0.4.3','tls-2.1.6','serialise-0.2.6.1','cborg-0.2.10.0'],['http-client-tls-0.3.6.4','tls-2.1.6','serialise-0.2.6.1','cborg-0.2.10.0'],['http-client-tls-0.3.6.4','crypton-connection-0.4.3','tls-2.1.6','serialise-0.2.6.1','cborg-0.2.10.0'],['http-client-tls-0.3.6.4','tls-2.1.6','serialise-0.2.6.1','cborg-0.2.10.0']]

yes
</samp></pre>
</details>
<p>It looks like my project only depends on <code>cborg-0.2.10.0</code> via <code>http-client-tls-0.3.6.4</code>.
Let’s verify that more concisely.</p>
<samp>| ?- <kbd>assertz((transitively_depends_on(X, Y) :- depends_on(X, Y))).</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>
yes
</samp></pre>
</details>
<samp>| ?- <kbd>assertz((transitively_depends_on(X, Z) :- depends_on(X, Y), transitively_depends_on(Y, Z))).</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>
yes
</samp></pre>
</details>
<samp>| ?- <kbd>setof(Dep, Packages^Package^(project_packages(Packages), member(Package, Packages), depends_on(Package, Dep), \+ member(Dep, Packages), transitively_depends_on(Dep, 'cborg-0.2.10.0')), Results).</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>
Results = ['http-client-tls-0.3.6.4']

yes
</samp></pre>
</details>
<h2 toc:omit_children="true" id="thoughts-and-ideas"><a href="#thoughts-and-ideas">Thoughts and ideas</a></h2>
<h3 id="include-build-tool-dependencies-in-the-graph"><a href="#include-build-tool-dependencies-in-the-graph">Include build tool dependencies in the graph</a></h3>
<p>I didn’t manage to figure out how my project transitively depends on <code>happy</code> because it’s probably used as a build tool somewhere.
The GHC package database doesn’t seem to store build tool information,
so the next step would be to find all my dependencies’ Cabal files and include <a href="https://cabal.readthedocs.io/en/3.4/cabal-package.html#pkg-field-build-tool-depends"><code>build-tool-depends</code></a> information in my Prolog facts.</p>
<h3 id="create-a-dependency-graph-for-all-of-hackage"><a href="#create-a-dependency-graph-for-all-of-hackage">Create a dependency graph for all of Hackage</a></h3>
<p>To really test the performance of this sort of query language, build a facts database for the entirety of Hackage
by extracting Cabal files from the Hackage index.</p>
<h3 id="use-datalog-to-query-the-nix-store"><a href="#use-datalog-to-query-the-nix-store">Use Datalog to query the Nix store</a></h3>
<p>The Nix store’s dependency graph was already <a href="#why-depends-inspiration">on my mind</a>.
What’s it like to query with Datalog?
It will probably be easier than Hackage, because Nix derivations are stored in JSON whereas Hackage uses the Cabal format.</p>
<h3 id="datalog--postgres"><a href="#datalog--postgres">Datalog &amp; Postgres?</a></h3>
<p>I really enjoyed writing these Prolog queries. They make SQL seem clunky in comparison.
I’m be interested in trying Datalog for some typical <a href="https://en.wikipedia.org/wiki/Online_transaction_processing">“OLTP”</a> / “CRUD” applications,
and it would be nice to avoid reinventing DBMS wheels.</p>
<ul>
<li>I’d love to try a Datalog frontend for Postgres.</li>
<li>Failing that, a Datalog to SQL compiler would work.</li>
</ul>
<h3 id="standalone-relational-storage-engines"><a href="#standalone-relational-storage-engines">Standalone relational storage engines?</a></h3>
<p>It would be cool if relational databases like Postgres and SQLite had explicitly decoupled storage engines.
My (lay) impression is that these are monolithic systems that aren’t intended to multiple frontends to the same underlying storage.</p>
<p>A standalone relational storage engine would be a C library that efficiently stores and searches records on disk or in memory.
This library can then be used by a DBMS for storage management.
Because it’s a standalone library, you’re no longer locked in to that particular DBMS.
If I want a Datalog frontend, I can write it using the same storage library and have something that’s compatible with existing databases.</p>
<p>The pieces are probably all there to do this with something like Postgres;
the storage format is <a href="https://www.postgresql.org/docs/current/storage.html">well-documented</a> and I wouldn’t be surprised if it was appropriately decoupled in the Postgres codebase.
But I feel like the monolithic style of DBMSs discourage this kind of thinking.
In contrast, imagine something like “<a href="https://zeromq.org/">ZeroMQ</a> for database storage”.</p>
    ]]></content>
    
</entry>
<entry>
    <title>Context menus</title>
    <link href="https://blog.ielliott.io/context-menus" />
    
    <id>https://blog.ielliott.io/context-menus</id>
    
    <published>2025-07-01T05:25:00Z</published>
    <updated>2025-07-01T05:25:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/context-menus"><![CDATA[<p>I got an email that had an unfamiliar time zone in it.
My intuition said that if I selected the text and right-clicked then I’d be closer to knowing what the corresponding local time was.
When I did, the best option I found was to search the web.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/context-menus"><![CDATA[
      
      <div class="text-with-figure">
<div class="text-with-figure__text">
<p>I got an email that had an unfamiliar time zone in it.
My intuition said that if I selected the text and right-clicked then I’d be closer to knowing what the corresponding local time was.
When I did, the best option I found was to search the web.</p>
<p><a href="https://kagi.com/search?q=12pp+PST">The Kagi search</a> <em>was</em> helpful, but I shouldn’t need internet access to compute an answer.</p>
<p>Wouldn’t it be cool if I could install a program that added this feature to relevant context menus?
And not only in Thunderbird, but in <em>every</em> program that has text and context menus?</p>
</div>
<figure class="text-with-figure__figure" style="width: 12rem;">
<img src="./images/thunderbird-context-menu.png" alt="The text &quot;12pm PST&quot; selected. A context menu lists some possible actions, including searching the web for it.">
<figcaption>
Thunderbird’s context menu for a text selection
</figcaption>
</figure>
</div>
    ]]></content>
    
</entry>
<entry>
    <title>Playing with GHC package databases</title>
    <link href="https://blog.ielliott.io/playing-with-ghc-package-databases" />
    
    <id>https://blog.ielliott.io/playing-with-ghc-package-databases</id>
    
    <published>2025-07-01T04:30:00Z</published>
    <updated>2025-07-01T04:30:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/playing-with-ghc-package-databases"><![CDATA[<p>I wanted to do some dependency analysis of a Haskell project,
and I wanted to see what it was like without installing a Cabal-specific tool such as
<a href="https://hackage.haskell.org/package/cabal-plan"><code>cabal-plan</code></a> (which works fine).
Here’s what I played around with.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/playing-with-ghc-package-databases"><![CDATA[
      
      <div id="toc" style="text-wrap: auto;">
<h3>Contents</h3>
<ul>
<li><a href="#finding-the-ghc-package-database-used-by-cabal">Finding the GHC package database used by Cabal</a></li>
<li><a href="#package-database-analysis">Package database analysis</a></li>
<li><a href="#thoughts-and-ideas">Thoughts and ideas</a></li>
</ul>
</div>
<p>I wanted to do some dependency analysis of a Haskell project,
and I wanted to see what it was like without installing a Cabal-specific tool such as
<a href="https://hackage.haskell.org/package/cabal-plan"><code>cabal-plan</code></a> (which works fine).
Here’s what I played around with.</p>
<h2 id="finding-the-ghc-package-database-used-by-cabal"><a href="#finding-the-ghc-package-database-used-by-cabal">Finding the GHC package database used by Cabal</a></h2>
<p>When building Haskell code with GHC and Cabal,
Cabal manages <a href="https://ghc.gitlab.haskell.org/ghc/doc/users_guide/packages.html">GHC package databases</a> for your project.
Cabal uses the <a href="https://ghc.gitlab.haskell.org/ghc/doc/users_guide/packages.html#envvar-GHC_ENVIRONMENT"><code>GHC_ENVIRONMENT</code></a> environment variable to communicate package information to GHC.</p>
<p>Inspect the variable via <code>cabal exec</code>:</p>
<samp>$ <kbd>cabal exec -- printenv GHC_ENVIRONMENT</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>/home/isaac/scotty/dist-newstyle/tmp/environment.-42133/.ghc.environment.x86_64-linux-9.6.6
</samp></pre>
</details>
<p>It’s a temporary file that’s cleaned up after <code>cabal</code> exits:</p>
<samp>$ <kbd>cat $(cabal exec -- printenv GHC_ENVIRONMENT)</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>cat: /home/isaac/scotty/dist-newstyle/tmp/environment.-42668/.ghc.environment.x86_64-linux-9.6.6: No such file or directory
</samp></pre>
</details>
<p>So to read the file’s contents:</p>
<samp>$ <kbd>cabal exec -- bash -c 'cat $(printenv GHC_ENVIRONMENT) | wc -l'</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>167
</samp></pre>
</details>
<samp>$ <kbd>cabal exec -- bash -c 'cat $(printenv GHC_ENVIRONMENT) | head -n 20'</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>&#x2D;&#x2D; This is a GHC environment file written by cabal. This means you can
&#x2D;&#x2D; run ghc or ghci and get the environment of the project as a whole.
&#x2D;&#x2D; But you still need to use cabal repl $target to get the environment
&#x2D;&#x2D; of specific components (libs, exes, tests etc) because each one can
&#x2D;&#x2D; have its own source dirs, cpp flags etc.
&#x2D;&#x2D;
clear-package-db
global-package-db
package-db /home/isaac/.local/state/cabal/store/ghc-9.6.6/package.db
package-db /home/isaac/scotty/dist-newstyle/packagedb/ghc-9.6.6
package-id scotty-0.22-inplace
package-id aeson-2.2.3.0-22b3a92d15c9e101394040ae41246b217864b9947aefa8650ea84ae86f886a71
package-id OneTuple-0.4.2-7fce57870ab38b77b68efd7d8a8c569b5646e38fd6083c48482d84b2cbb4b9f8
package-id base-4.18.2.1
package-id ghc-bignum-1.3
package-id ghc-prim-0.10.0
package-id rts-1.0.2
package-id template-haskell-2.20.0.0
package-id ghc-boot-th-9.6.6
package-id pretty-1.1.3.6
</samp></pre>
</details>
<p>This means that <code>cabal build</code> et al. will use package databases <code>/home/isaac/.local/state/cabal/store/ghc-9.6.6/package.db</code> and <code>/home/isaac/scotty/dist-newstyle/packagedb/ghc-9.6.6</code>.</p>
<p>Now that we know the package database paths, we can use <a href="https://ghc.gitlab.haskell.org/ghc/doc/users_guide/packages.html#package-management-the-ghc-pkg-command"><code>ghc-pkg</code></a> to query them.</p>
<samp>$ <kbd>ghc-pkg --package-db=/home/isaac/.local/state/cabal/store/ghc-9.6.6/package.db list | wc -l</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>675
</samp></pre>
</details>
<p>I think this is just the package database for everything I’ve downloaded from Hackage to date.</p>
<p>What about the other one?</p>
<samp>$ <kbd>ghc-pkg --package-db=/home/isaac/scotty/dist-newstyle/packagedb/ghc-9.6.6 list</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>WARNING: there are broken packages.  Run &apos;ghc-pkg-9.6.6 check&apos; for more details.
/home/isaac/scotty/dist-newstyle/packagedb/ghc-9.6.6
    scotty-0.22
</samp></pre>
</details>
<samp>$ <kbd>ghc-pkg --package-db=/home/isaac/scotty/dist-newstyle/packagedb/ghc-9.6.6 check</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>There are problems in package scotty-0.22:
  Warning: haddock-interfaces: /home/isaac/scotty/dist-newstyle/build/x86_64-linux/ghc-9.6.6/scotty-0.22/doc/html/scotty/scotty.haddock doesn&apos;t exist or isn&apos;t a file
  Warning: haddock-html: /home/isaac/scotty/dist-newstyle/build/x86_64-linux/ghc-9.6.6/scotty-0.22/doc/html/scotty doesn&apos;t exist or isn&apos;t a directory
  dependency "aeson-2.2.3.0-22b3a92d15c9e101394040ae41246b217864b9947aefa8650ea84ae86f886a71" doesn&apos;t exist
  dependency "blaze-builder-0.4.2.3-12eefb9a1a78be6e7022945ab259dd32e85b6ca455fcd003fe4e06f9179e7992" doesn&apos;t exist
  ...
  dependency "wai-extra-3.1.17-819af7b672ea64d23961a97b5fe6cf5ca65cb2c5510c7d77bbddee954acb10c5" doesn&apos;t exist
  dependency "warp-3.4.7-7055965423ff64562e3affc843bcceaf11f389a4a74c6cd55ed3940f63322e42" doesn&apos;t exist
Warning: include-dirs: /nix/store/97cajcan6faqj0kr9zhl0jin38vzcnhi-ghc-9.6.6/lib/ghc-9.6.6/lib/../lib/x86_64-linux-ghc-9.6.6/directory-1.3.8.5/include doesn&apos;t exist or isn&apos;t a directory

The following packages are broken, either because they have a problem
listed above, or because they depend on a broken package.
scotty-0.22
</samp></pre>
</details>
<p>It’s missing a bunch of dependencies. Let’s use both package databases together:</p>
<samp>$ <kbd>ghc-pkg --package-db=/home/isaac/.local/state/cabal/store/ghc-9.6.6/package.db --package-db=/home/isaac/scotty/dist-newstyle/packagedb/ghc-9.6.6 list</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>/home/isaac/.local/state/cabal/store/ghc-9.6.6/package.db
    Cabal-3.12.1.0
    Cabal-syntax-3.12.1.0
    ChasingBottoms-1.3.1.15
    Glob-0.10.2
    HUnit-1.6.2.0
    JuicyPixels-3.3.9
    JuicyPixels-3.3.9
    MemoTrie-0.6.11
    OneTuple-0.4.2
    ...
    xml-types-0.3.8
    yaml-0.11.11.2
    yaml-0.11.11.2
    zip-archive-0.4.3.2
    zlib-0.7.1.0
    zlib-0.7.1.0

/home/isaac/scotty/dist-newstyle/packagedb/ghc-9.6.6
    scotty-0.22
</samp></pre>
</details>
<p>The second package database is just for this project’s packages.</p>
<h2 id="package-database-analysis"><a href="#package-database-analysis">Package database analysis</a></h2>
<p>Now that we’ve got a working package database stack, we can play around.
First, save the dependency graph in a flexible format:</p>
<samp>$ <kbd>ghc-pkg --package-db=/home/isaac/scotty/dist-newstyle/packagedb/ghc-9.6.6 --simple-output field scotty-0.22 id</kbd></samp>
<details open>
<summary>
(output)
</summary>
<pre><samp>scotty-0.22-inplace
</samp></pre>
</details>
<details class="shell-command">
<summary>
<samp>$ <kbd>python3 - &gt; scotty-0.22-inplace.json &lt;&lt;EOF</kbd></samp>
</summary>
<pre><samp>$ <kbd>python3 - > scotty-0.22-inplace.json &lt;&lt;EOF
import json
import subprocess

package_name = "scotty-0.22-inplace"

def graph(package_id):
  result = {}

  def go(package_id):
    depends = subprocess.run(
      [
        "ghc-pkg",
        "&#x2D;&#x2D;no-user-package-db",
        "&#x2D;&#x2D;package-db=/home/isaac/.local/state/cabal/store/ghc-9.6.6/package.db",
        "&#x2D;&#x2D;package-db=/home/isaac/scotty/dist-newstyle/packagedb/ghc-9.6.6",
        "&#x2D;&#x2D;ipid",
        "&#x2D;&#x2D;simple-output",
        "field",
        package_id,
        "depends"
      ],
      capture_output=True,
      text=True
    ).stdout.strip()

    split_depends = [depend_id for depend_id in map(lambda x: x.strip(), depends.split(" ")) if depend_id]
  
    result[package_id] = split_depends
    for depend_id in split_depends:
      if depend_id not in result:
        go(depend_id)

  go(package_id)

  return result

print(json.dumps(graph(package_name), sort_keys=True))
EOF
</kbd></samp></pre>
</details>
<details>
<summary>
(no output)
</summary>
</details>
<p>Then visualise the graph:</p>
<details class="shell-command">
<summary>
<samp>$ <kbd>{ python3 - | dot -Tsvg &gt; scotty-0.22-inplace.svg; } &lt;&lt;EOF</kbd></samp>
</summary>
<pre><samp>$ <kbd>{ python3 - | dot -Tsvg > scotty-0.22-inplace.svg; } &lt;&lt;EOF
import json

file_name = "scotty-0.22-inplace.json"

def quote(x):
  return f&apos;"{x}"&apos;

def strip_id(x):
  [*prefix, last] = x.split("-")
  return "-".join(prefix)

def dot(graph):
  for k, v in graph.items():
    joined_depends = "{" + " ".join([quote(strip_id(depend_id)) for depend_id in v]) + "}"    
    print(f"{quote(strip_id(k))} -> {joined_depends}")

print("digraph {")
with open(file_name) as file:
  dot(json.load(file))
print("}")
EOF
</kbd></samp></pre>
</details>
<details>
<summary>
(no output)
</summary>
</details>
<samp>$ <kbd>dot -Tsvg scotty-0.22-inplace.dot &gt; deps-scotty-0.22-inplace.svg</kbd></samp>
<details open>
<summary>
(output)
</summary>
<figure>
<img src="./images/deps-scotty-0.22-inplace.svg" height="360" data-pan-zoom="">
<figcaption>
Dependency graph for my checkout of <a href="https://hackage.haskell.org/package/scotty-0.22">scotty-0.22</a>
</figcaption>
</figure>
</details>
</ul>
<p>Let’s order them by transitive closure size:</p>
<details class="shell-command">
<summary>
<samp>$ <kbd>{ python3 - | sort -h | tail; } &lt;&lt;EOF</kbd></samp>
</summary>
<pre><samp>$ <kbd>{ python3 - | sort -h | tail; } &lt;&lt;EOF
import json

file_name = "scotty-0.22-inplace.json"

def transitive_closure(graph, root):
  seen = set()

  def go(node):
    if node in seen:
      return set()
    else:
      seen.add(node)
      return set.union({node}, *[go(adjacent_node) for adjacent_node in graph[node]])

  return go(root)

def transitive_closure_sizes(graph):
  for node in graph.keys():
    print(len(transitive_closure(graph, node)), node)

with open(file_name) as file:
  transitive_closure_sizes(json.load(file))
EOF
</kbd></samp></pre>
</details>
<details open>
<summary>
(output)
</summary>
<pre><samp>25 streaming-commons-0.2.2.6-3f522fa5f939db1b55145657d311c943006edb86009c26092909366b2ee75aee
28 semigroupoids-6.0.1-9dd89e384571d44fb22e2fb7072578c66e77815638622ba98f23f5f4b84282b2
33 http-api-data-0.6.1-44cab653536eecb6e1a4492b7db5ddb55bad7134ef4df6f7019d9b0d933fbf23
33 wai-logger-2.5.0-afde5370b0becd5a59db9b87d40363205352d3d195d9f7f6918e6141c5790f9b
34 http2-5.3.9-e85f1b676925943caace1517467efd2cb267ded07cdb15141f4d23011f166d32
36 semialign-1.3.1-54b91e33817ae4935235d4a598fa09630b1344e5fc8ef634e7b379a9abcbae4b
58 aeson-2.2.3.0-22b3a92d15c9e101394040ae41246b217864b9947aefa8650ea84ae86f886a71
67 warp-3.4.7-7055965423ff64562e3affc843bcceaf11f389a4a74c6cd55ed3940f63322e42
117 wai-extra-3.1.17-819af7b672ea64d23961a97b5fe6cf5ca65cb2c5510c7d77bbddee954acb10c5
127 scotty-0.22-inplace
</samp></pre>
</details>
<p><code>wai-extra</code> sure has a lot of dependencies. Which dependencies are unique to <code>wai-extra</code>?</p>
<details class="shell-command">
<summary>
<samp>$ <kbd>{ python3 - | sort; } &lt;&lt;EOF</kbd></samp>
</summary>
<pre><samp>$ <kbd>{ python3 - | sort; } &lt;&lt;EOF
import json

file_name = "scotty-0.22-inplace.json"

def transitive_closure(graph, root, excluding={}):
  def go(node, excluding):
      result = {node}
      for adjacent_node in graph[node]:
        if adjacent_node not in excluding:
          result = set.union(result, go(adjacent_node, {}))
      return result

  return go(root, excluding)

with open(file_name) as file:
  graph = json.load(file)

wai_extra = "wai-extra-3.1.17-819af7b672ea64d23961a97b5fe6cf5ca65cb2c5510c7d77bbddee954acb10c5"
a = transitive_closure(graph, "scotty-0.22-inplace", {wai_extra})
b = transitive_closure(graph, wai_extra)
for element in b - a:
  print(element)
EOF
</kbd></samp></pre>
</details>
<details open>
<summary>
(output)
</summary>
<pre><samp>ansi-terminal-1.1.2-d813dc9a9ddcc8fe046981ae4cf16e97851f81b47627fe62d97deeea8b3a895c
ansi-terminal-types-1.1-f5259ee8039cb2e4f0745aaf2a221ac1804976d88721a0bbf03fa589fc1da7b9
base64-bytestring-1.2.1.0-1d3b0d9233998c8db4e03792dfcb571d3630c51818122c1df384f008255859d8
call-stack-0.4.0-8d31f8ae063fb95797e807de0dcca55432203fbdb07105abf4ba4f3a0860ef74
colour-2.3.6-24e30114cf117673f32f0197751def539bd8f5410de72a299de6885591f0fdfd
easy-file-0.2.5-30a028cc4c6fd7862bc8a47d31985a45218a10d4422c035a8fff3448ec4801dc
fast-logger-3.2.5-ba361b4be97b9b35499712d8f507906cdebc3cc5a1036133240c2e08b10a6a56
HUnit-1.6.2.0-df563d5b792be11ca4e58e4d870dddc83eb4e3f9a52334bc71194d682e05b20e
unix-compat-0.7.3-32201a092fc238f3eccb0914b80c185b8d1d4f773a1dd8f2fb5563b7b6d76bda
wai-extra-3.1.17-819af7b672ea64d23961a97b5fe6cf5ca65cb2c5510c7d77bbddee954acb10c5
wai-logger-2.5.0-afde5370b0becd5a59db9b87d40363205352d3d195d9f7f6918e6141c5790f9b
</samp></pre>
</details>
<p>And if we exclude <code>wai-extra</code>, then which dependencies are unique to <code>aeson</code>?</p>
<details class="shell-command">
<summary>
<samp>$ <kbd>{ python3 - | sort; } &lt;&lt;EOF</kbd></samp>
</summary>
<pre><samp>$ <kbd>{ python3 - | sort; } &lt;&lt;EOF
import json

file_name = "scotty-0.22-inplace.json"

def transitive_closure(graph, root, excluding={}):
  def go(node, excluding):
      result = {node}
      for adjacent_node in graph[node]:
        if adjacent_node not in excluding:
          result = set.union(result, go(adjacent_node, {}))
      return result

  return go(root, excluding)

with open(file_name) as file:
  graph = json.load(file)

wai_extra = "wai-extra-3.1.17-819af7b672ea64d23961a97b5fe6cf5ca65cb2c5510c7d77bbddee954acb10c5"
aeson = "aeson-2.2.3.0-22b3a92d15c9e101394040ae41246b217864b9947aefa8650ea84ae86f886a71"
a = transitive_closure(graph, "scotty-0.22-inplace", {aeson,wai_extra})
b = transitive_closure(graph, aeson)
for element in b - a:
  print(element)
EOF
</kbd></samp></pre>
</details>
<details open>
<summary>
(output)
</summary>
<pre><samp>aeson-2.2.3.0-22b3a92d15c9e101394040ae41246b217864b9947aefa8650ea84ae86f886a71
assoc-1.1.1-91e0bc5b0eb5cdad4ce61452d6155d452cac5d786af875847301af32b934f253
bifunctors-5.6.2-cdf5e9d975abe82ed95add7544f5e6e48940d9e7f5951180b3dcacba9ad97937
character-ps-0.1-87eb2c6d1a544cf19d3be82f4399a28864ed8d7542e2de535b42fc8056a9d5c9
comonad-5.0.9-ec7e1b2474b620c56c05b73796c5dce04e68441d59edb217a30e1bb77e48c942
contravariant-1.5.5-6a59bcf4e69a8f892227aa56684b44d1735596355500cba48bb9556495af7a7a
data-fix-0.3.4-7d597ffefc30f7a138edc24dc1e03bebbf99520c26ee1af6318a323b3bc526a8
distributive-0.6.2.1-c13d5bb01b367cf9f192f77e0e5d90e4a6cda304cc5697ea52f5925c88d80b68
dlist-1.0-3f3e12dbb9340ca35fec4abee0f3e37d2efd77c79010ac403b24fe666a366fda
generically-0.1.1-f217083ba3fc5ebe022288f26b2a769e0b39440c221ecae8e8a84336b627c7fa
indexed-traversable-0.1.4-86fd612af77d0540ca42d5223fc9600bb51bf5e9f6d7ffe74f58e4eb6346acc2
indexed-traversable-instances-0.1.2-9831eee38ead8950ef755ff4425a82f4e822cb30329849d29c400d6fdfa9f48f
network-uri-2.6.4.2-f34e13d200dc845553cbada86fe6571c3b03af72b2be5233ec82dae21b560e8e
OneTuple-0.4.2-7fce57870ab38b77b68efd7d8a8c569b5646e38fd6083c48482d84b2cbb4b9f8
parsec-3.1.16.1
QuickCheck-2.15.0.1-c94e2ced9f5f0dd3f594a04519b82805819b2b0379b9af74da0bd21726807fc4
semialign-1.3.1-54b91e33817ae4935235d4a598fa09630b1344e5fc8ef634e7b379a9abcbae4b
semigroupoids-6.0.1-9dd89e384571d44fb22e2fb7072578c66e77815638622ba98f23f5f4b84282b2
StateVar-1.2.2-0d5154d6e1d634f4e8767a7881908c34dedbc6cace8d2fe22118078ab9b12887
strict-0.5.1-0102bddb9fe467e451549ac50f5ddc9163563e9539eeed3d6ee08b5d9346b275
text-short-0.1.6-662ac4f8bb2f349ae6d506b1834638219dce4453004fb077f179cb16b3c6e2b3
th-abstraction-0.7.1.0-961929bb0a2cfcc168b2a8158c99139722497385235d4359a7dcd4d353e5957a
th-compat-0.1.6-0605ad4fe4730665b7b05d178af0de7dd3cb888b4f51e363b3ce11c5e6c1b6ed
these-1.2.1-2c66a71e09a4f0d388e0495b32ada8a64764c07eb4b90121bb1482fc8aefd0a1
vector-0.13.2.0-36660ea3d0c11b81bc8d2fd49bdacdb1fe74eb64b339694a83e4d99c8cad7b5a
vector-stream-0.1.0.1-545e7e06db03dece0246a6bae97757021fce10507a67c3d3b06190d1367c5623
witherable-0.5-bd7f0d1e02c3180a6977cb316a3de72faf9fa6ec35511c54587f2ae6843f9d9a
</samp></pre>
</details>
<h2 id="thoughts-and-ideas"><a href="#thoughts-and-ideas">Thoughts and ideas</a></h2>
<ul>
<li><p>Calling <code>ghc-pkg</code> repeatedly to build the dependency graph was slow.
A faster way would be to write a Haskell program that reuses GHC / <code>ghc-pkg</code> package database code.</p></li>
<li><p>“Querying” the dependency graph in Python was tedious.
I wonder if there’s a better way?</p>
<ul>
<li>Import into SQLite?
<ul>
<li>Is there a graph-first equivalent of SQLite?</li>
</ul></li>
<li>Something based on Datalog?
<ul>
<li>Follow up: <a href="https://blog.ielliott.io/exploring-graphs-with-prolog">Exploring a dependency graph with Prolog</a></li>
</ul></li>
<li><a href="https://glean.software/docs/introduction/">Glean</a> and <a href="https://glean.software/docs/angle/intro/">Angle</a>?</li>
</ul></li>
<li><p>Wouldn’t it be cool if this document was generated from a literate program?</p></li>
</ul>
<script src="/res/img-pan-zoom.js"></script>
    ]]></content>
    
</entry>
<entry>
    <title>2024 Project Review</title>
    <link href="https://blog.ielliott.io/2024-project-review" />
    
    <id>https://blog.ielliott.io/2024-project-review</id>
    
    <published>2025-02-26T22:45:05Z</published>
    <updated>2025-02-26T22:45:05Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/2024-project-review"><![CDATA[<p>Reflections on 2024's hobby projects.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/2024-project-review"><![CDATA[
      
      <div id="toc" style="white-space: normal;">
<h3>Contents</h3>
<ul>
<li><a href="#blog">Blog</a></li>
<li><a href="#self-hosted-github-ci-runners">Self-hosted GitHub CI runners</a></li>
<li><a href="#citools"><code>citools</code></a></li>
<li><a href="#using-linear-algebra-for-quantitative-queries">Using linear algebra for quantitative queries</a></li>
<li><a href="#travel-planning-web-app">Travel planning web app</a></li>
<li><a href="#nix-flakes-for-nixos-configurations">Nix Flakes for NixOS configurations</a></li>
<li><a href="#basque"><code>basque</code></a></li>
<li><a href="#opstools"><code>opstools</code></a></li>
<li><a href="#improved-cd-command">Improved <code>cd</code> command</a></li>
<li><a href="#git-format-staged"><code>git-format-staged</code></a></li>
<li><a href="#git-cli-overhaul">Git CLI overhaul</a></li>
<li><a href="#haskell-build-tool-experiments">Haskell build tool experiments</a></li>
<li><a href="#beginner-os-dev">Beginner OS dev</a></li>
<li><a href="#functional-web-routing">Functional web routing</a></li>
<li><a href="#desktop-environment-theming">Desktop environment theming</a></li>
<li><a href="#safe-sized-types-and-coinduction-in-agda">Safe sized types and coinduction in Agda</a></li>
<li><a href="#xeval"><code>xeval</code></a></li>
<li><a href="#haskell-code-manipulation-via-ghc-exactprint">Haskell code manipulation via <code>ghc-exactprint</code></a></li>
<li><a href="#haskell-syntax-tools"><code>haskell-syntax-tools</code></a></li>
<li><a href="#template-monoid"><code>template-monoid</code></a></li>
<li><a href="#hedge"><code>hedge</code></a></li>
<li><a href="#replace-taffybar-with-polybar">Replace Taffybar with Polybar</a></li>
<li><a href="#neuron-performance-improvements"><code>neuron</code> performance improvements</a></li>
</ul>
</div>
<h2 id="blog"><a href="#blog">Blog</a></h2>
<p><em>ongoing</em></p>
<p>Posts:</p>
<ul>
<li><a href="https://blog.ielliott.io/troubleshooting-lightdms-test-mode">Troubleshooting LightDM’s test mode</a></li>
<li><a href="https://blog.ielliott.io/per-project-nix-substituters">Per-project Nix substituters</a></li>
<li><a href="https://blog.ielliott.io/sized-types-and-coinduction-in-safe-agda">Sized types and coinduction in Safe Adga</a></li>
<li><a href="https://blog.ielliott.io/unfettering-the-imagination">Unfettering the imagination</a></li>
</ul>
<p>My <a href="https://github.com/LightAndLight/lightandlight.github.io">Hakyll setup</a> now has documentation.
Someone asked my permission use my blog as a template, which I gave.
I added documentation so that they (and whoever else) can use all the features.</p>
<h2 id="self-hosted-github-ci-runners"><a href="#self-hosted-github-ci-runners">Self-hosted GitHub CI runners</a></h2>
<p><em>January</em></p>
<p><a href="https://github.com/LightAndLight/github-runner" class="uri">https://github.com/LightAndLight/github-runner</a> (private)</p>
<p>I started playing around with self-hosting a GitHub CI runners on <a href="https://www.digitalocean.com/">DigitalOcean</a> for use in <a href="https://ipso.dev">Ipso</a>.
The repo is private because I committed secrets, some encrypted and unencrypted, while I figured out how I wanted to do secret management.
It uses <a href="https://github.com/getsops/sops">SOPS</a> with <a href="https://github.com/FiloSottile/age">age</a> for secrets,
<a href="https://www.terraform.io/">Terraform</a> for provisioning infrastructure,
and <a href="https://nixos.org/">NixOS</a> for machine configurations.</p>
<h2 id="citools"><a href="#citools"><code>citools</code></a></h2>
<p><em>January</em></p>
<p><a href="https://github.com/LightAndLight/citools" class="uri">https://github.com/LightAndLight/citools</a></p>
<p>Nix derivations and <a href="https://ipso.dev">Ipso</a> scripts that I want to reuse outside of <a href="#self-hosted-github-ci-runners">Self-hosted GitHub CI runners</a>.</p>
<h2 id="using-linear-algebra-for-quantitative-queries"><a href="#using-linear-algebra-for-quantitative-queries">Using linear algebra for quantitative queries</a></h2>
<p><em>January</em></p>
<p><a href="https://github.com/LightAndLight/misc/tree/main/20240112-linear-algebra-queries" class="uri">https://github.com/LightAndLight/misc/tree/main/20240112-linear-algebra-queries</a></p>
<p>Linear algebra on semirings sort-of generalises relational algebra.
This is a little bit of Agda code where I played around with the idea.
See the README for an overview.</p>
<p>Related reading:</p>
<ul>
<li><a href="https://repositorio.inesctec.pt/server/api/core/bitstreams/a533c8a1-0d69-4517-87e9-060503d3dc48/content">A linear algebra approach to OLAP</a></li>
<li><a href="https://www.di.uminho.pt/~jno/ps/infoblender16sl.pdf">Towards a linear algebra semantics for SQL</a></li>
<li><a href="https://web.archive.org/web/20160305153614id_/http://www.cl.cam.ac.uk/~sd601/papers/semirings.pdf">Fun with Semirings</a></li>
</ul>
<h2 id="travel-planning-web-app"><a href="#travel-planning-web-app">Travel planning web app</a></h2>
<p><em>February—March</em></p>
<p><a href="https://gitlab.com/LightAndLight/ix-travel" class="uri">https://gitlab.com/LightAndLight/ix-travel</a> (private)</p>
<p>I wanted to collaborate on software with my partner, who’s interested in the UX design and product management side of things.
She suggested we create a web app for travel planning.
We don’t have much beyond signup, login, and deployment, because I got distracted by creating my own frameworks (see <a href="#basque"><code>basque</code></a>, <a href="#functional-web-routing">Functional web routing</a>, <a href="#hedge"><code>hedge</code></a>).
It was fun to work together and I look forward to resuming it at some point.</p>
<h2 id="nix-flakes-for-nixos-configurations"><a href="#nix-flakes-for-nixos-configurations">Nix Flakes for NixOS configurations</a></h2>
<p><em>March</em></p>
<p><a href="https://github.com/LightAndLight/personal-configs" class="uri">https://github.com/LightAndLight/personal-configs</a></p>
<p>I use NixOS and <a href="https://nix-community.github.io/home-manager/index.xhtml#ch-introduction"><code>home-manager</code></a> to manage configuration across all my computers.
The <a href="https://nixos-and-flakes.thiscute.world/">NixOS &amp; Flakes Book</a> showed me how to manage my entire system configuration, including my <code>home-manager</code> configs, with Flakes.</p>
<p>The main advantage of this approach is Flakes’ external dependency management.
Rather than having
<a href="https://nix.dev/manual/nix/2.18/language/builtins.html?highlight=fetchtarball#builtins-fetchTarball"><code>fetchTarball</code></a>s
littered everywhere, all my dependencies are listed in a
<a href="https://github.com/LightAndLight/personal-configs/blob/547a8a4c3864c6318601111896a4f1a6ee101089/flake.nix#L1-L37">single place</a>,
and can be updated with a
<a href="https://nix.dev/manual/nix/2.24/command-ref/new-cli/nix3-flake-update.html">single command</a>.</p>
<h2 id="basque"><a href="#basque"><code>basque</code></a></h2>
<p><em>March</em></p>
<p><a href="https://github.com/LightAndLight/basque" class="uri">https://github.com/LightAndLight/basque</a> (private)</p>
<p><code>basque</code> is a Haskell database library, inspired by <a href="https://haskell-beam.github.io/beam/"><code>beam</code></a>’s shortcomings.
I love the core premise of <code>beam</code>—a table is defined as a Haskell record—but I don’t like the library’s complexity, poor error messages, and SQL generation gotchas.
<a href="https://hackage.haskell.org/package/rel8"><code>rel8</code></a> also tackles these issues, but I haven’t tried it yet.</p>
<p>One fun feature of <code>basque</code> is auto-migration, which was inspired by <a href="https://hackage.haskell.org/package/beam-automigrate"><code>beam-automigrate</code></a>.
Auto-migration diffs the actual schema against the expected schema, and executes a series of schema changes to bring the actual schema up-to-date.
This is really nice for local iteration, but it can be finnicky in production.
I’m still figuring out how to think about auto-migration and whether/how it should be combined with traditional database migrations.</p>
<p><code>basque</code> is private because it’s incomplete and it overlaps with some code in <a href="#hedge"><code>hedge</code></a>.
<code>hedge</code> attempts to improve on <a href="#basque"><code>basque</code></a>’s database migrations.
It has auto-migration for local development, static migrations for production, and a tool that generates static migrations based on your code changes.</p>
<h2 id="opstools"><a href="#opstools"><code>opstools</code></a></h2>
<p><em>March</em></p>
<p><a href="https://github.com/LightAndLight/opstools" class="uri">https://github.com/LightAndLight/opstools</a></p>
<p>Tools that I created while working on <a href="#travel-planning-web-app">Travel planning web app</a>, that I think are broadly useful:</p>
<ul>
<li><code>sshgen</code> - Simplified interface to ssh-keygen for stdin/stdout-based SSH key generation.</li>
<li><code>tmply</code> - Pass temporary data to a process and clean up after.</li>
<li><code>retry</code> - Retry a failing command.</li>
</ul>
<h2 id="improved-cd-command"><a href="#improved-cd-command">Improved <code>cd</code> command</a></h2>
<p><em>March</em></p>
<p><a href="https://github.com/LightAndLight/personal-configs/blob/547a8a4c3864c6318601111896a4f1a6ee101089/home/fish.nix#L18-L30" class="uri">https://github.com/LightAndLight/personal-configs/blob/547a8a4c3864c6318601111896a4f1a6ee101089/home/fish.nix#L18-L30</a></p>
<p>I almost always run <code>ls</code> after <code>cd</code> to get an overview of the new directory’s contents.
For large directories, the <code>ls</code> output takes up too much screen space.
I overrode Fish’s <code>cd</code> command to list the first 20 items after I <code>cd</code>.
If there are no more than 20 items, this looks like normal <code>ls</code> output.
But if there are more than 20 items, the final line says <code>(20 of X items shown)</code>.</p>
<p>The <code>ls</code> output is truncated using <code>head</code>: <code>ls | head -n 20</code>.
This creates a new problem; it removes the column formatting that <code>ls</code> produces when you call it from a terminal.
I tried using the <a href="https://www.man7.org/linux/man-pages/man1/column.1.html"><code>column</code></a> program, but it didn’t support terminal escape sequences.
It counted the escape sequences as visible characters, which threw off the column calculations.
This seemed like a simple kind of program, so I wrote my own: <a href="https://github.com/LightAndLight/columnize"><code>columnize</code></a>.</p>
<h2 id="git-format-staged"><a href="#git-format-staged"><code>git-format-staged</code></a></h2>
<p><em>March</em></p>
<ul>
<li><a href="https://github.com/LightAndLight/git-format-staged" class="uri">https://github.com/LightAndLight/git-format-staged</a></li>
<li><a href="https://github.com/LightAndLight/git-ustash" class="uri">https://github.com/LightAndLight/git-ustash</a> (precursor to <code>git-format-staged</code>)</li>
</ul>
<p>Modify staged files, backporting changes onto their unstaged versions. Useful for formatting files as part of a <a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks">pre-commit hook</a>.</p>
<p>This is something I’ve wanted when writing <a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks">pre-commit hooks</a> that do auto-formatting.
The goal of a pre-commit auto-formatter is to format staged files without affecting any other files.
<code>git diff --cached --name-only</code> gives the list of staged files, but if you <em>just</em> format them without any other preparation then you can cause issues with unstaged files.
For example, if you use <code>git add -p</code> to stage a file using a partial patch, then you will have the rest of the file unstaged.
How to format just the staged copy of the file?
The unstaged version (with the remainder of the changes) is the only one on disk.
Using <code>git stash --keep-index</code> almost does the right thing; it gets the unstaged files out of the way so it looks like you are free to work on just the staged files.
Unfortunately it also stashes the staged files, so that when you auto-format the staged files, re-add them to the index, and pop from the stash, the formatted files are overwritten by the stash.
<a href="https://stackoverflow.com/a/71222518/2884502">This answer on StackOverflow</a> looked promising, but <code>git stash push --staged</code> fails with an error when I use it in the <code>git add -p</code> aforementioned situation.</p>
<h2 id="git-cli-overhaul"><a href="#git-cli-overhaul">Git CLI overhaul</a></h2>
<p><em>April</em></p>
<p><a href="https://github.com/LightAndLight/personal-configs/blob/547a8a4c3864c6318601111896a4f1a6ee101089/home/git.nix#L26-L403" class="uri">https://github.com/LightAndLight/personal-configs/blob/547a8a4c3864c6318601111896a4f1a6ee101089/home/git.nix#L26-L403</a></p>
<p>I used Nix (via <code>home-manager</code>) to set up dozens of <a href="https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases">Git aliases</a>, essentially creating my own alternative Git CLI.
Read the detailed listing (with demo videos) <a href="/my-git-cli-overhaul">here</a>.</p>
<h2 id="haskell-build-tool-experiments"><a href="#haskell-build-tool-experiments">Haskell build tool experiments</a></h2>
<p><em>April</em></p>
<p><a href="https://github.com/LightAndLight/hbuild" class="uri">https://github.com/LightAndLight/hbuild</a> (private)</p>
<p>I experimented with building Haskell packages from scratch, without <a href="https://www.haskell.org/cabal/">Cabal</a> (or <a href="https://haskellstack.org">Stack</a>).
I started by writing a Makefile that can build an example Haskell library and executable.
It directly uses the <a href="https://downloads.haskell.org/ghc/latest/docs/users_guide/packages.html">GHC package database</a> for dependencies
and generates a package database entry for the library.
After that I wrote a build tool that reads a <a href="https://toml.io">TOML</a> manifest and uses <a href="https://shakebuild.com">Shake</a> for incremental rebuilds.
The next step would be to download dependencies from Hackage.</p>
<p>This code is private because experimenting with alternative Haskell build tools seems like a sensitive topic.
I remember a bunch of Cabal/Stack drama from ~10 years ago and don’t want to repeat it.
That said, I think Cabal is not a great build tool, and I want to see if I can do better.
My main focuses are user experience, performance, and implementation simplicity.
If I create something that I’m willing to use, and it feels good and is well written, then I’ll make it public.
Then I’ll use it as an exemplar to motivate improvements to Cabal.
For projects as large and old as Cabal, I feel like it’s better to demonstrate what things should be like with a prototype instead of arguing over hypothetical improvements.</p>
<h2 id="beginner-os-dev"><a href="#beginner-os-dev">Beginner OS dev</a></h2>
<p><em>June</em></p>
<p><a href="https://github.com/LightAndLight/learn-os" class="uri">https://github.com/LightAndLight/learn-os</a></p>
<p>I started learning about OS development from first principles.
So far I have a barebones UEFI program that loads a kernel which prints <code>hello from kernel!</code> to a serial device.</p>
<p>I remember being fascinated by <a href="https://en.wikipedia.org/wiki/Virtual_memory">virtual memory</a>,
the <a href="https://en.wikipedia.org/wiki/Page_table">page table</a>,
and how the kernel manages it all.
Since CPU instructions are also read from memory, they’re also subject to address translation.
This means kernel code that changes the page table could accidentally alter its own control flow.
In order for the kernel to continue normally after changing the page table,
the region of code responsible for switching needs to live at the same virtual addresses in the old and new page tables.</p>
<p>I also got <a href="https://github.com/rust-osdev/uefi-rs/pull/1187">a small pull request</a> merged into <a href="https://github.com/rust-osdev/uefi-rs"><code>uefi-rs</code></a>.
I want to do more of these small fixes for open source libraries, because it feels like if we all do this sort of thing then we’ll end up with very high quality software.</p>
<h2 id="functional-web-routing"><a href="#functional-web-routing">Functional web routing</a></h2>
<p><em>July</em></p>
<p><a href="https://github.com/LightAndLight/misc/tree/main/20240704-functional-web-routing" class="uri">https://github.com/LightAndLight/misc/tree/main/20240704-functional-web-routing</a></p>
<p>This started out as an attempt to do trie-based URL routing on well-typed web route specifications,
and grew into a <a href="https://servant.dev">Servant</a>-like web framework,
but with a much smaller type-level DSL.
I quite like it, and I’ve been expanding on it in another project, <a href="#hedge"><code>hedge</code></a>.</p>
<h2 id="desktop-environment-theming"><a href="#desktop-environment-theming">Desktop environment theming</a></h2>
<p><em>August</em></p>
<ul>
<li><a href="https://github.com/LightAndLight/personal-configs/blob/cdb00b793006e72768b2f6a6b8d0622ab7cd4c33/home/taffybar/taffybar.css" class="uri">https://github.com/LightAndLight/personal-configs/blob/cdb00b793006e72768b2f6a6b8d0622ab7cd4c33/home/taffybar/taffybar.css</a></li>
<li><a href="https://github.com/LightAndLight/personal-configs/blob/cdb00b793006e72768b2f6a6b8d0622ab7cd4c33/home/xsession/xmonad.hs#L29" class="uri">https://github.com/LightAndLight/personal-configs/blob/cdb00b793006e72768b2f6a6b8d0622ab7cd4c33/home/xsession/xmonad.hs#L29</a></li>
<li><a href="https://github.com/LightAndLight/personal-configs/blob/cdb00b793006e72768b2f6a6b8d0622ab7cd4c33/home/xsession/default.nix#L14-L23" class="uri">https://github.com/LightAndLight/personal-configs/blob/cdb00b793006e72768b2f6a6b8d0622ab7cd4c33/home/xsession/default.nix#L14-L23</a></li>
</ul>
<p>I set up a consistent colour scheme (based on <a href="https://github.com/morhetz/gruvbox">Gruvbox</a>) across
<a href="https://xmonad.org/">Xmonad</a>,
<a href="https://github.com/taffybar/taffybar">Taffybar</a>,
and
<a href="https://tools.suckless.org/dmenu/">dmenu</a>.
I used <a href="https://github.com/yshui/picom">picom</a> to add rounded corners to my X windows.
See <a href="#replace-taffybar-with-polybar">Replace Taffybar with Polybar</a> for a screenshot; I did more customisation later in the year.</p>
<h2 id="safe-sized-types-and-coinduction-in-agda"><a href="#safe-sized-types-and-coinduction-in-agda">Safe sized types and coinduction in Agda</a></h2>
<p><em>August</em></p>
<ul>
<li><a href="https://github.com/LightAndLight/agda-safe-sized-types" class="uri">https://github.com/LightAndLight/agda-safe-sized-types</a></li>
<li><a href="https://blog.ielliott.io/sized-types-and-coinduction-in-safe-agda" class="uri">https://blog.ielliott.io/sized-types-and-coinduction-in-safe-agda</a></li>
</ul>
<p>Coinduction is important for total languages like Agda because can be used to write and reason about continuing (essentially non-terminating) processes.
A few of the official coinductive methods in Agda are unsound, but I think I found an approach that implements coinduction using sound extensions.</p>
<p>The practical motivation for all of this is writing parser combinators in Agda.
The naive (i.e. “just port it from Haskell”) approach doesn’t work due to Agda’s restrictive termination checker.
Coinduction plus a slightly safer set of combinators makes everything work.</p>
<h2 id="xeval"><a href="#xeval"><code>xeval</code></a></h2>
<p><em>September</em></p>
<p><a href="https://github.com/LightAndLight/xeval" class="uri">https://github.com/LightAndLight/xeval</a></p>
<p><code>xeval</code> is a program that reads the X11 selection, evaluates it if it’s an arithmetic expression, and replaces the selection with the result.
I bound it to <code>mod+e</code> in my XMonad config.
I’ve noticed that it doesn’t work very well because different programs have slightly different ways of managing the X11 selection.
Testing it with one kind of text input (e.g. the Firefox URL bar) doesn’t guarantee that it works with another kind of text input
(e.g. the Chromium URL bar).</p>
<h2 id="haskell-code-manipulation-via-ghc-exactprint"><a href="#haskell-code-manipulation-via-ghc-exactprint">Haskell code manipulation via <code>ghc-exactprint</code></a></h2>
<p><em>October</em></p>
<p><a href="https://github.com/LightAndLight/misc/tree/main/20241019-ghc-exactprint" class="uri">https://github.com/LightAndLight/misc/tree/main/20241019-ghc-exactprint</a></p>
<p>This was an attempt to use <a href="https://hackage.haskell.org/package/ghc">GHC API</a> and <a href="https://hackage.haskell.org/package/ghc-exactprint"><code>ghc-exactprint</code></a> for formatting-preserving syntax tranformations.
I’ve applying what I’ve learned to to <a href="https://guides.rubyonrails.org/command_line.html#bin-rails-generate">Rails-style boilerplate generation</a> for a Haskell web framework (see <a href="#hedge"><code>hedge</code></a>).</p>
<p><code>rails generate controller CONTROLLER ACTION*</code> creates a new controller by generating some files from templates,
and it registers the actions’ routes by adding some lines to an existing Ruby file (<code>routes.rb</code>).
This piqued my interest because it’s not just adding those lines to the end of a file; it’s somewhat syntax-aware.</p>
<p>It’s <a href="https://stackoverflow.com/a/39742150/2884502">a little more finnicky</a> to add an action to an existing controller via the CLI.
I think most people just write the code.
I want a workflow in Haskell where there are a few conventional modules that a CLI tool can programmatically update to add a new endpoint.</p>
<p>The practise program I wrote can add fields to a record while preserving formatting:</p>
<table>
<thead>
<th>
Input
</th>
<th>
Action
</th>
<th>
Output
</th>
</thead>
<tbody>
<tr>
<td>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">X</span> <span class="ot">=</span> <span class="dt">X</span> {<span class="ot"> a ::</span> <span class="dt">Int</span>,<span class="ot"> b ::</span> <span class="dt">Int</span> }</span></code></pre></div>
</td>
<td>
<p>add <code>c :: Int</code></p>
</td>
<td>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">X</span> <span class="ot">=</span> <span class="dt">X</span> {<span class="ot"> a ::</span> <span class="dt">Int</span>,<span class="ot"> b ::</span> <span class="dt">Int</span>,<span class="ot"> c ::</span> <span class="dt">Int</span> }</span></code></pre></div>
</td>
</tr>
<tr>
<td>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">X</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">X</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> a ::</span> <span class="dt">Int</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> b ::</span> <span class="dt">Int</span> </span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</td>
<td>
<p>add <code>c :: Int</code></p>
</td>
<td>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">X</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">X</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> a ::</span> <span class="dt">Int</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> b ::</span> <span class="dt">Int</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> c ::</span> <span class="dt">Int</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</td>
</tr>
<tr>
<td>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">X</span> <span class="ot">=</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">X</span>{</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="ot">    a ::</span> <span class="dt">Int</span>,</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="ot">    b ::</span> <span class="dt">Int</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</td>
<td>
<p>add <code>c :: Int</code></p>
</td>
<td>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">X</span> <span class="ot">=</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">X</span>{</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="ot">    a ::</span> <span class="dt">Int</span>,</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="ot">    b ::</span> <span class="dt">Int</span>,</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="ot">    c ::</span> <span class="dt">Int</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</td>
</tr>
</tbody>
</table>
<h2 id="haskell-syntax-tools"><a href="#haskell-syntax-tools"><code>haskell-syntax-tools</code></a></h2>
<p><em>October</em></p>
<p><a href="https://github.com/LightAndLight/haskell-syntax-tools" class="uri">https://github.com/LightAndLight/haskell-syntax-tools</a></p>
<p>After <a href="#haskell-code-manipulation-via-ghc-exactprint">Haskell code manipulation via <code>ghc-exactprint</code></a>,
I created some support libraries to help me write scaffolding and boilerplate generation for <a href="#hedge"><code>hedge</code></a>.
I initially tried to use <a href="https://hackage.haskell.org/package/ghc-exactprint"><code>ghc-exactprint</code></a>,
but I found its documentation was lacking and its API wasn’t intuitive.
It was easier to start from scratch.</p>
<p><code>haskell-syntax-tools</code> includes:
<a href="https://github.com/LightAndLight/haskell-syntax-tools/blob/2981581fbddc6011f41558ae693e21e1ec556509/ghc-lens/src/GHC/Lens.hs">optics for the GHC AST</a>,
<a href="https://github.com/LightAndLight/haskell-syntax-tools/blob/2981581fbddc6011f41558ae693e21e1ec556509/ghc-exactprint-transform/src/GHC/ExactPrint/Transform.hs">common syntax manipulations</a>,
and <a href="https://github.com/LightAndLight/haskell-syntax-tools/blob/2981581fbddc6011f41558ae693e21e1ec556509/ghc-exactprint-syntax/src/GHC/ExactPrint/QQ.hs">a quasiquoter for writing GHC AST fragments</a>.</p>
<h2 id="template-monoid"><a href="#template-monoid"><code>template-monoid</code></a></h2>
<p><em>October</em></p>
<p><a href="https://github.com/LightAndLight/template-monoid" class="uri">https://github.com/LightAndLight/template-monoid</a></p>
<p><code>template-monoid</code> is a simple Haskell library for combining monoidal values with effects.
Quoting the README:</p>
<blockquote>
<p>The <code>Template</code> type defined in this library already exists in <code>base</code> as <a href="https://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Monoid.html#t:Ap"><code>Ap</code></a>.
I’ve created a new package because I think it deserves to stand on its own as a concept, with explanations and code examples.</p>
<p>The description of the <code>Ap</code> type is:</p>
<blockquote>
<p>This data type witnesses the lifting of a Monoid into an Applicative pointwise.</p>
</blockquote>
<p>While accurate, this description is rather dry and doesn’t spark my curiosity or gesture at potential uses for this datatype.</p>
</blockquote>
<p><code>Template</code> has an <code>IsString</code> instance, so you can write code like <code>("Hello, " &lt;&gt; Template readLine) :: Template IO String</code>.
I’ve used it to generate SQL queries in <a href="#basque"><code>basque</code></a> and <a href="#hedge"><code>hedge</code></a>.
SQL queries are mostly strings, but if you want to escape identifiers then the strings have to live in <code>ReaderT Connection IO</code>.
<code>Template</code> makes this quite pretty, e.g. <code>("SELECT * FROM " &lt;&gt; escape tableName &lt;&gt; " WHERE id = 1") :: Template (ReaderT Connection IO) String</code>.</p>
<h2 id="hedge"><a href="#hedge"><code>hedge</code></a></h2>
<p><em>October—November</em></p>
<p><a href="https://github.com/LightAndLight/hedge" class="uri">https://github.com/LightAndLight/hedge</a> (private)</p>
<p><code>hedge</code> is my attempt at a web framework that combines my favourite parts of
<a href="https://rubyonrails.org/">Ruby on Rails</a> with my favourite parts of
<a href="https://www.haskell.org/">Haskell</a> and functional programming.
My taste for web frameworks has become more refined,
and I want a framework that has all of my favourite features of various frameworks with none of the incidental downsides.</p>
<p>For example:</p>
<ul>
<li>I like Rails’ “convention over configuration”, “everything is Ruby”, and use of scaffolding tools, but I dislike Ruby’s type system.</li>
<li>I like <a href="https://www.servant.dev/">Servant</a>’s type safety, but dislike its implementation complexity.</li>
<li>I like <a href="https://www.yesodweb.com/">Yesod</a>’s boilerplate generation, but dislike its use of Template Haskell DSLs for this.</li>
<li>I like <a href="https://ihp.digitallyinduced.com/">IHP</a>’s comprehensiveness and focus on developer experience, but disagree with a lot of its software engineering choices.</li>
</ul>
<p><code>hedge</code> is an expression of some of my software engineering and web development values,
and it will probably live in a new corner of the design space when it comes to Haskell web frameworks.
It’s currently private because I don’t like having half-finished public repositories.
I’ll open source it when I think it’s usable.</p>
<h2 id="replace-taffybar-with-polybar"><a href="#replace-taffybar-with-polybar">Replace Taffybar with Polybar</a></h2>
<p><em>December</em></p>
<p>I got a new laptop and started playing with battery usage optimisation.
I soon noticed that Taffybar consistently used 100% of a CPU core while idle.
After a bit of searching I couldn’t find anything that suggested improvements, so I started looking for alternatives.
I found <a href="https://github.com/polybar/polybar">polybar</a>, and <a href="https://github.com/LightAndLight/personal-configs/commit/009d2b68332725421aa16b5c00bcc4fbef185565">tried it out</a>.
It works great.
Here’s my current config: <a href="https://github.com/LightAndLight/personal-configs/blob/3e340b4d93359386bdda492cb72dfcc8b0922e17/home/polybar/config.ini.nix" class="uri">https://github.com/LightAndLight/personal-configs/blob/3e340b4d93359386bdda492cb72dfcc8b0922e17/home/polybar/config.ini.nix</a>.</p>
<figure>
<img src="./images/2025-02-27-desktop.png">
<figcaption>
Screenshot of my desktop.
There are two Polybar bars; one at the top of the screen and one at the bottom.
The top bar shows my X workspace selection, and the current date and time.
The bottom bar shows my computer’s resource usage: CPU, RAM, and network traffic.
</figcaption>
</figure>
<h2 id="neuron-performance-improvements"><a href="#neuron-performance-improvements"><code>neuron</code> performance improvements</a></h2>
<p><em>December</em></p>
<p><a href="https://github.com/LightAndLight/neuron" class="uri">https://github.com/LightAndLight/neuron</a></p>
<p><a href="https://github.com/srid/neuron"><code>neuron</code></a> is a simple <a href="https://en.wikipedia.org/wiki/Zettelkasten">Zettelkasten</a> tool
that I’ve been using for a couple of years.
It’s no longer maintained, but it has worked fine for me for a long time.
Recently it started getting really slow, and I decided to investigate.</p>
<p>I eventually figured out that it was traversing the entirety of <a href="https://direnv.net/"><code>.direnv</code></a>,
which contained a checkout of <a href="https://github.com/nixos/nixpkgs"><code>nixpkgs</code></a>
—a repo consisting of hundreds of thousands of files.
The code created a full file tree in memory then filtered out entries such as hidden directories.
I fixed it by applying the filepath filters while constructing the in-memory file tree,
so that it would skip <code>.direnv</code> and never even look at its contents.</p>
<p>I read a similar story recently:
<a href="https://randomascii.wordpress.com/2022/09/29/why-modern-software-is-slow-windows-voice-recorder/">Why Modern Software is Slow–Windows Voice Recorder</a>.</p>
    ]]></content>
    
</entry>
<entry>
    <title>My Git CLI overhaul</title>
    <link href="https://blog.ielliott.io/my-git-cli-overhaul" />
    
    <id>https://blog.ielliott.io/my-git-cli-overhaul</id>
    
    <published>2025-02-26T22:45:00Z</published>
    <updated>2025-02-26T22:45:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/my-git-cli-overhaul"><![CDATA[<p>Showing off the Git aliases I use daily.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/my-git-cli-overhaul"><![CDATA[
      
      <p><em>I split this out of <a href="/2024-project-review">my 2024 project review</a> because it got too long.</em></p>
<p>Last year I improved my daily Git experience by writing a bunch of aliases.
Here’s a reference for what I’ve done so far (<a href="https://github.com/LightAndLight/personal-configs/blob/3e340b4d93359386bdda492cb72dfcc8b0922e17/home/git.nix#L26">Nix configs</a>).</p>
<div id="toc" style="min-width: 15rem; white-space: normal; column-count: 2;">
<h3>Contents</h3>
<ul>
<li><a href="#meta">Meta</a></li>
<li><a href="#git-a"><code>git a</code></a></li>
<li><a href="#git-amend"><code>git amend</code></a></li>
<li><a href="#git-ap"><code>git ap</code></a></li>
<li><a href="#git-au"><code>git au</code></a></li>
<li><a href="#git-br"><code>git br</code></a></li>
<li><a href="#git-co"><code>git co</code></a></li>
<li><a href="#git-coe"><code>git coe</code></a></li>
<li><a href="#git-com"><code>git com</code></a></li>
<li><a href="#git-ch"><code>git ch</code></a></li>
<li><a href="#git-chn"><code>git chn</code></a></li>
<li><a href="#git-d"><code>git d</code></a></li>
<li><a href="#git-ds"><code>git ds</code></a></li>
<li><a href="#git-f"><code>git f</code></a></li>
<li><a href="#git-l"><code>git l</code></a></li>
<li><a href="#git-lg"><code>git lg</code></a></li>
<li><a href="#git-p"><code>git p</code></a></li>
<li><a href="#git-pa"><code>git pa</code></a></li>
<li><a href="#git-pf"><code>git pf</code></a></li>
<li><a href="#git-r"><code>git r</code></a></li>
<li><a href="#git-re"><code>git re</code></a></li>
<li><a href="#git-rec"><code>git rec</code></a></li>
<li><a href="#git-rei"><code>git rei</code></a></li>
<li><a href="#git-reword"><code>git reword</code></a></li>
<li><a href="#git-st"><code>git st</code></a></li>
<li><a href="#git-spop"><code>git spop</code></a></li>
<li><a href="#git-spush"><code>git spush</code></a></li>
<li><a href="#git-undo"><code>git undo</code></a></li>
</ul>
</div>
<h2 id="meta"><a href="#meta">Meta</a></h2>
<ul>
<li><p>Every command that changes repo state prints the updated state using <a href="#git-st"><code>git st</code></a>.</p></li>
<li><p>Every command that acts on a Git object, like a commit or a branch, opens a fuzzy finder if the object is omitted.</p></li>
</ul>
<h2 id="git-a"><a href="#git-a"><code>git a</code></a></h2>
<p><code>git a FILE+</code> - Stage the given <code>FILE</code>s.</p>
<p>Inverse: <a href="#git-r"><code>git r</code></a>.</p>
<h2 id="git-amend"><a href="#git-amend"><code>git amend</code></a></h2>
<p><code>git amend</code> - Add the currently staged changes to a given commit.</p>
<figure>
<x-asciinema-cast data-src="./images/git-amend.cast" data-idle-time-limit="1" aria-details="git-amend-details"></x-asciinema-cast>
<figcaption id="git-amend-details">
<p><a href="https://asciinema.org/">Asciinema</a> cast of <code>git amend</code> (<a href="./images/git-amend.cast">source</a>).
After a file is staged, <code>git amend</code> brings up a fuzzy-finder showing recent commits.
A commit is selected, and the staged change inserted into that commit.</p>
<noscript>
Enable JavaScript to view the cast.
</noscript>
</figcaption>
</figure>
<h2 id="git-ap"><a href="#git-ap"><code>git ap</code></a></h2>
<p><code>git ap</code> - Stage files using <a href="https://git-scm.com/docs/git-add#_interactive_mode">interactive patch mode</a>.</p>
<h2 id="git-au"><a href="#git-au"><code>git au</code></a></h2>
<p><code>git au</code> - Stage all modified files.</p>
<h2 id="git-br"><a href="#git-br"><code>git br</code></a></h2>
<p><code>git br OPTION*</code> - Branch management.</p>
<p>Prints the current branch name if <code>OPTION</code>s are ommitted. Otherwise, <code>OPTION</code>s are passed to <a href="https://git-scm.com/docs/git-branch"><code>git branch</code></a>.</p>
<h2 id="git-co"><a href="#git-co"><code>git co</code></a></h2>
<p><code>git co</code> - Commit staged files, opening an editor for the commit message.</p>
<p>Inverse: <a href="#git-undo"><code>git undo</code></a>.</p>
<h2 id="git-coe"><a href="#git-coe"><code>git coe</code></a></h2>
<p><code>git coe MESSAGE</code> - Create an empty commit with message <code>MESSAGE</code>.</p>
<p>Inverse: <a href="#git-undo"><code>git undo</code></a>.</p>
<h2 id="git-com"><a href="#git-com"><code>git com</code></a></h2>
<p><code>git com MESSAGE</code> - Commit staged files with message <code>MESSAGE</code>.</p>
<p>Inverse: <a href="#git-undo"><code>git undo</code></a>.</p>
<h2 id="git-ch"><a href="#git-ch"><code>git ch</code></a></h2>
<p><code>git ch BRANCH?</code> - Switch to a branch.</p>
<figure>
<x-asciinema-cast data-src="./images/git-ch.cast" data-idle-time-limit="1" aria-details="git-ch-details"></x-asciinema-cast>
<figcaption id="git-ch-details">
<p><a href="https://asciinema.org/">Asciinema</a> cast of <code>git ch</code> (<a href="./images/git-ch.cast">source</a>).
<code>git ch</code> brings up a fuzzy-finder showing available branches.
A branch is selected and switched to.</p>
<noscript>
Enable JavaScript to view the cast.
</noscript>
</figcaption>
</figure>
<h2 id="git-chn"><a href="#git-chn"><code>git chn</code></a></h2>
<p><code>git chn BRANCH</code> - Create and switch to branch <code>BRANCH</code>.</p>
<h2 id="git-d"><a href="#git-d"><code>git d</code></a></h2>
<p><code>git d</code> - Diff unstaged files against staged and committed files.</p>
<h2 id="git-ds"><a href="#git-ds"><code>git ds</code></a></h2>
<p><code>git ds</code> - Diff staged files against committed files.</p>
<h2 id="git-f"><a href="#git-f"><code>git f</code></a></h2>
<p><code>git f</code> - Fetch new changes, and show whether recent commits have diverged.</p>
<figure>
<img src="./images/git-f-diverged.png" aria-details="git-f-details" style="width: auto; max-height: 100px;">
<figcaption id="git-f-details">
Screenshot of <code>git f</code>, where the local changes have diverged from the remote changes.
The commits are listed in the same format as <a href="#git-l"><code>git l</code></a>, but both the local and remote commits are listed, and an ASCII graph highlights the divergence.
</figcaption>
</figure>
<h2 id="git-l"><a href="#git-l"><code>git l</code></a></h2>
<p><code>git l</code> - Display the 20 most recent commits.</p>
<figure>
<img src="./images/git-l.png" aria-details="git-l-details">
<figcaption id="git-l-details">
Screenshot of <code>git l</code>.
Commits are listed one per line.
Each line includes: a shortened commit hash, the first line of the commit message, the time since the commit was made, and any branches that point to the commit.
</figcaption>
</figure>
<h2 id="git-lg"><a href="#git-lg"><code>git lg</code></a></h2>
<p><code>git lg</code> - Display the 20 most recent commits using an ASCII graph.</p>
<p>See <a href="#git-f"><code>git f</code></a> for a screenshot of an ASCII graph.</p>
<h2 id="git-p"><a href="#git-p"><code>git p</code></a></h2>
<p><code>git p</code> - Push the current branch.</p>
<h2 id="git-pa"><a href="#git-pa"><code>git pa</code></a></h2>
<p><code>git pa</code> - Push all branches.</p>
<h2 id="git-pf"><a href="#git-pf"><code>git pf</code></a></h2>
<p><code>git pf</code> - Force-push the current branch.</p>
<h2 id="git-r"><a href="#git-r"><code>git r</code></a></h2>
<p><code>git r FILE+</code> - Unstage staged <code>FILE</code>s.</p>
<h2 id="git-re"><a href="#git-re"><code>git re</code></a></h2>
<p><code>git re OPTION*</code> - Call <a href="https://git-scm.com/docs/git-rebase"><code>git rebase</code></a> with <code>OPTION</code>s.</p>
<h2 id="git-rec"><a href="#git-rec"><code>git rec</code></a></h2>
<p><code>git rec</code> - Alias for <code>git rebase --continue</code>.</p>
<h2 id="git-rei"><a href="#git-rei"><code>git rei</code></a></h2>
<p><code>git rei COMMIT?</code> - Start an <a href="https://git-scm.com/docs/git-rebase#_interactive_mode">interactive rebase</a>.</p>
<p>Uses <code>COMMIT</code> as the base commit if provided.
Otherwise, launches a fuzzy finder to select the base commit.</p>
<h2 id="git-reword"><a href="#git-reword"><code>git reword</code></a></h2>
<p><code>git reword COMMIT?</code> - Edit a commit message.</p>
<p>Edits <code>COMMIT</code> if provided.
Otherwise, launches a fuzzy finder to select the commit.</p>
<figure>
<x-asciinema-cast data-src="./images/git-reword.cast" data-idle-time-limit="1" aria-details="git-reword-details"></x-asciinema-cast>
<figcaption id="git-reword-details">
<p><a href="https://asciinema.org/">Asciinema</a> cast of <code>git reword</code> (<a href="./images/git-reword.cast">source</a>).
<code>git reword</code> brings up a fuzzy-finder showing recent commits.
A commit is selected, and an editor opens containing that commit’s message.
The message is edited, the editor saved then closed, updating the commit’s message.</p>
<noscript>
Enable JavaScript to view the cast.
</noscript>
</figcaption>
</figure>
<h2 id="git-st"><a href="#git-st"><code>git st</code></a></h2>
<p><code>git st</code> - Print the repo’s state.</p>
<figure>
<img src="./images/git-st.png" aria-details="git-st-details">
<figcaption id="git-st-details">
Screenshot of <code>git st</code>.
Modified files are marked with a red “M”, staged files are marked with a green “A”, and new files are marked witha a red “??”.
The command also lists any unpushed commits.
</figcaption>
</figure>
<h2 id="git-spop"><a href="#git-spop"><code>git spop</code></a></h2>
<p><code>git spop</code> - Alias for <code>git stash pop</code>.</p>
<h2 id="git-spush"><a href="#git-spush"><code>git spush</code></a></h2>
<p><code>git spush</code> - Alias for <code>git stash push</code>.</p>
<h2 id="git-undo"><a href="#git-undo"><code>git undo</code></a></h2>
<p><code>git undo</code> - Remove the most recent commit, staging its files.</p>
<p>Inverse of <a href="#git-co"><code>git co</code></a>, <a href="#git-coe"><code>git coe</code></a>, <a href="#git-com"><code>git com</code></a>.</p>
    ]]></content>
    
</entry>
<entry>
    <title>In Praise of ZSA</title>
    <link href="https://blog.ielliott.io/in-praise-of-zsa" />
    
    <id>https://blog.ielliott.io/in-praise-of-zsa</id>
    
    <published>2025-01-11T00:00:00Z</published>
    <updated>2025-01-11T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/in-praise-of-zsa"><![CDATA[<p><a href="https://www.zsa.io">ZSA</a> makes ergonomic keyboards.
I own two of their <a href="https://ergodox-ez.com/">Ergodox EZ</a>s (one for work, one for home) which I use every day.
They also publish an <a href="https://www.zsa.io/the-ergo">email newsletter</a> that I subscribe to and happily read.
In the <a href="https://mailchi.mp/zsa/the-ergo-75">December 2024 issue</a>, they noted that ZSA doesn’t advertise (see <a href="https://www.zsa.io/trust">Why trust us | zsa.io</a>), and essentially rely on recommendations from customers.
I like ZSA and hope they continue to be successful, so this short article is my attempt to give something back to them without buying <em>another</em> keyboard.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/in-praise-of-zsa"><![CDATA[
      
      <p><a href="https://www.zsa.io">ZSA</a> makes ergonomic keyboards.
I own two of their <a href="https://ergodox-ez.com/">Ergodox EZ</a>s (one for work, one for home) which I use every day.
They also publish an <a href="https://www.zsa.io/the-ergo">email newsletter</a> that I subscribe to and happily read.
In the <a href="https://mailchi.mp/zsa/the-ergo-75">December 2024 issue</a>, they noted that ZSA doesn’t advertise (see <a href="https://www.zsa.io/trust">Why trust us | zsa.io</a>), and essentially rely on recommendations from customers.
I like ZSA and hope they continue to be successful, so this short article is my attempt to give something back to them without buying <em>another</em> keyboard.</p>
<p>My Ergodox EZs are great. I edit my configuration using
<a href="https://configure.zsa.io/">ZSA’s online configuration tool</a>
(here’s <a href="https://configure.zsa.io/ergodox-ez/layouts/60G6R/latest/0">my layout</a>)
and then flash a keyboard using <a href="https://github.com/zsa/wally">wally</a>.
The firmware has a lot of great features and has allowed me to turn my keyboard into a personalised programming tool.</p>
<div style="display: flex; flex-direction: row; gap: 1rem;">
<figure>
<a href="./images/zsa-1.png"><img src="./images/zsa-1.png"></a>
<figcaption>
My base keyboard layout
</figcaption>
</figure>
<figure>
<a href="./images/zsa-2.png"><img src="./images/zsa-2.png"></a>
<figcaption>
My symbols layer
</figcaption>
</figure>
</div>
<p>I expect to use these keyboards for decades, and that’s something I can’t often say about products I own.
I think planned obsolescence is increasing because it can give businesses more consistent revenue over decades.
Why sell something for <code>$X</code> that will last 20 years, when you can sell one for <code>0.15 * $X</code> that lasts 2 years and have a customer purchase 10 (and throw out 9) over the same period?
Of course, the business metrics that improve as a result come at the expense of the customer and the world at large.</p>
<p>In contrast, ZSA really seems to be doing business right: existing to serve its customers, rather than existing to self-perpetuate.
My Ergodox EZ is <em>for me</em> in a way that many other technology products I use are not.
Every newsletter email I get from conveys sincerity and integrity that I find increasingly lacking in businesses, especially in the technology industry.
I wish them all the best.</p>
    ]]></content>
    
</entry>
<entry>
    <title>Unfettering the imagination</title>
    <link href="https://blog.ielliott.io/unfettering-the-imagination" />
    
    <id>https://blog.ielliott.io/unfettering-the-imagination</id>
    
    <published>2024-09-22T00:00:00Z</published>
    <updated>2024-09-22T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/unfettering-the-imagination"><![CDATA[<p><a href="https://github.com/LightAndLight/xeval"><code>xeval</code></a> is a small and not particularly useful program that arose from an important thought process.
This post the result of exploring that thought process—trying to articulate it to myself—but without writing too much on the topic.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/unfettering-the-imagination"><![CDATA[
      
      <p><a href="https://github.com/LightAndLight/xeval"><code>xeval</code></a> is a small and not particularly useful program that arose from an important thought process.
This post the result of exploring that thought process—trying to articulate it to myself—but without writing too much on the topic.</p>
<p>I want to gesture at what I’ve been thinking via a concrete example: the evolution of mobile phone controls.
We interacted with early mobile phones by pressing a fixed set of physical buttons, and in the mid-to-late 2000s switched to touch screens.
I imagine that in the early days of that transition it was all too easy to treat the touch screen as a canvas for virtual buttons.
But “thinking in buttons” misses the potential of touch screens.</p>
<p>For example, I’d suggest that no amount of “thinking in buttons” will lead one to consider using a swipe gesture as an input.
To have a chance at inventing “swipe”, one has to stop looking through the established “how” (buttons; discrete 2D regions with a binary input) and start from the “what” (e.g. asking for a new page to appear on the screen).
Only then does one have the freedom to imagine that dragging a finger across the display could correspond to dragging one page out of view and the next page into view.</p>
<p>And the <em>idea</em> of a touch screen required even more of this kind of imaginative freedom.
Moving from physical buttons to touch screens was a greater technological leap than from virtual touch screen buttons to swipe gestures,
so the idea of a touch screen would have seemed even more incredible in the absence of an implementation.
Yet this idea was still valuable 1, 5, or 10 years before it was possible to implement, because it set a direction for research.
To be able to have such ideas, one has to stop thinking so completely in terms of what is currently feasible.</p>
<p>When using a computing system to achieve a goal, so much of the “how” is dictated by software.
Software is designed and created by people, which means the rules enforced by the are necessarily more malleable than, say, physics or chemistry.
You have to “click X to close the window” not because that’s fundamentally how the universe works, but because people chose to make it so.
All of those concepts—clicking, virtual X button, closing, windows—were imagined by people and defined in software.</p>
<p>As a computer user, it’s easy for me to forget this.
When I learn that “software X can’t do Y”, I instinctively interpret this is a statement of possibility, like “you can’t build a perpetual motion machine”.
In most cases this instinct is wrong, and the reason that “software X can’t do Y” is because it just wasn’t built that way.
I also forget that being a programmer, I’m in as good a position as any to overcome whatever software problems I recognise.
I don’t have to be subject to my tools, because I can build my own.
It’s weird that I have to remind myself of this, because in general I enjoy improving the process of computing, and particularly programming.
Many of my areas of interest (programming languages, version control systems, operating systems, and databases, to name a few) are related to me wanting to improve my craft.</p>
<p>In the same way that “thinking-in-buttons” fails to capture the full potential of touch screens,
the things we take for granted about our current computing systems could put a limit on our progress in computing.
Dreaming is the impetus to break out of the local optimum.</p>
<p>At this point, I think I’m ready to state the idea I’ve been playing with in a succinct, general form:</p>
<p><strong>I suspect there’s a limit to the progress we can make from within any particular paradigm, and that technological leaps from come from inventing new paradigms.</strong>
<strong>These new paradigms are first imagined, irrespective of feasibility, while being grounded in our human needs and desires.</strong></p>
<p>The idea behind <code>xeval</code> came from trying this on.
I was typing a message and knew the formula for some number but didn’t want to do the arithmetic in my head.
I know “how” to use my computer to help: copy the arithmetic, boot up a calculation program in another window, paste the arithmetic, ask the program to compute the answer, copy the answer, then paste the answer into the original text.
But zooming out, I saw that the “what” is much simpler: I want to evaluate the formula I just typed.</p>
<p>So I allowed myself to dream of better ways.
What if I could just point at any editable text and say “evaluate this”?
It felt like a good idea regardless of what my system was capable of at the time.
This time I was lucky; I was able to get pretty close to the original idea using standard tools.
But I expect that if I keep thinking in this direction, I’ll come up with other good-feeling ideas that are less compatible with my current software paradigm, so I’ll have to do more work to make them real.</p>
    ]]></content>
    
</entry>
<entry>
    <title>Sized types and coinduction in Safe Agda</title>
    <link href="https://blog.ielliott.io/sized-types-and-coinduction-in-safe-agda" />
    
    <id>https://blog.ielliott.io/sized-types-and-coinduction-in-safe-agda</id>
    
    <published>2024-09-04T00:00:00Z</published>
    <updated>2024-09-04T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/sized-types-and-coinduction-in-safe-agda"><![CDATA[<p>Agda's <a href="https://agda.readthedocs.io/en/latest/language/sized-types.html">sized types</a> are inconsistent.
This post is about why I care and how I've worked around it.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/sized-types-and-coinduction-in-safe-agda"><![CDATA[
      
      <div id="toc">
<h3>Contents</h3>
<ul>
<li><a href="#background">Background</a></li>
<li><a href="#the-encoding">The encoding</a>
<ul>
<li><a href="#example-streams">Example: streams</a></li>
<li><a href="#example-colists">Example: (co)lists</a></li>
<li><a href="#summary">Summary</a></li>
</ul></li>
<li><a href="#proof">Proof</a></li>
<li><a href="#future-work">Future work</a></li>
<li><a href="#appendix-philosophical-ramblings">Appendix: philosophical ramblings</a>
<ul>
<li><a href="#infinity-as-an-object">Infinity as an object</a></li>
<li><a href="#codata-via-pi-types">Codata via <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Π</mi><annotation encoding="application/x-tex">\Pi</annotation></semantics></math>-types</a></li>
</ul></li>
</ul>
</div>
<p>Agda’s <a href="https://agda.readthedocs.io/en/latest/language/sized-types.html">sized types</a> are inconsistent.
This post is about why I care and how I’ve worked around it.
If you just want to read the code, go <a href="https://github.com/LightAndLight/agda-safe-sized-types">here</a>.</p>
<h2 id="background"><a href="#background">Background</a></h2>
<p>Here’s a <a href="https://agda.readthedocs.io/en/v2.7.0/language/coinduction.html">typical</a> coinductive type in Agda—a continuing stream:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">record</span> Stream <span class="ot">(</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">)</span> <span class="ot">:</span> <span class="dt">Set</span> <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">coinductive</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">field</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    head <span class="ot">:</span> A</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    tail <span class="ot">:</span> Stream A</span></code></pre></div>
<p>Some might describe <code>Stream</code> as an “infinite data structure”; an infinite list of <code>A</code>s.
I think of it as a sequential process that can always yield another <code>A</code>.</p>
<p>Coinductive types (codata for short) are important because they help us reason about potentially unending processes.
A stream has no end—if you try to collect all of its elements then you’ll never finish—and yet there are many useful terminating programs we can write involving streams.</p>
<p>The following function, <code>zipWith</code>, is an example of such a function.
It defines an output stream in terms of two input streams,
where each element of the output is the combination of the two input elements at that position.
It uses <a href="https://agda.readthedocs.io/en/latest/language/copatterns.html">copattern syntax</a>, which is essentially a syntax to define record values by cases.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="pp">{-# OPTIONS --guardedness #-}</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">open</span> Stream</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>zipWith <span class="ot">:</span> <span class="ot">{</span>A B C <span class="ot">:</span> <span class="dt">Set</span><span class="ot">}</span> <span class="ot">→</span> <span class="ot">(</span>A <span class="ot">→</span> B <span class="ot">→</span> C<span class="ot">)</span> <span class="ot">→</span> Stream A <span class="ot">→</span> Stream B <span class="ot">→</span> Stream C</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>head <span class="ot">(</span>zipWith f sa sb<span class="ot">)</span> <span class="ot">=</span> f <span class="ot">(</span>sa <span class="ot">.</span>head<span class="ot">)</span> <span class="ot">(</span>sb <span class="ot">.</span>head<span class="ot">)</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>tail <span class="ot">(</span>zipWith f sa sb<span class="ot">)</span> <span class="ot">=</span> zipWith f <span class="ot">(</span>sa <span class="ot">.</span>tail<span class="ot">)</span> <span class="ot">(</span>sb <span class="ot">.</span>tail<span class="ot">)</span></span></code></pre></div>
<p>In words:</p>
<ul>
<li>The head of <code>zipWith f sa sb</code> is the combination of <code>sa</code>’s head and <code>sb</code>’s head via <code>f</code></li>
<li>The tail of <code>zipWith f sa sb</code> is the the <code>zipWith</code>ed tails of <code>sa</code> and <code>sb</code>.</li>
</ul>
<p>The stream is <em>productive</em> the <code>head</code> case and the <code>tail</code> case always terminates.
Definitions like <code>head (zipWith f sa sb) = head (zipWith f sa sb)</code> and <code>tail (zipWith f sa sb) = tail (zipWith f sa sb)</code> are not productive because they create infinite loops.
And a function like <code>filter</code>:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>filter <span class="ot">:</span> <span class="ot">{</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">}</span> <span class="ot">→</span> <span class="ot">(</span>A <span class="ot">→</span> Bool<span class="ot">)</span> <span class="ot">→</span> Stream A <span class="ot">→</span> Stream A</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>head <span class="ot">(</span>filter f s<span class="ot">)</span> <span class="ot">=</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  if f <span class="ot">(</span>s <span class="ot">.</span>head<span class="ot">)</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  then s <span class="ot">.</span>head</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>  else <span class="ot">(</span>filter f <span class="ot">(</span>s <span class="ot">.</span>tail<span class="ot">))</span> <span class="ot">.</span>head</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>tail <span class="ot">(</span>filter f s<span class="ot">)</span> <span class="ot">=</span> filter f <span class="ot">(</span>s <span class="ot">.</span>tail<span class="ot">)</span></span></code></pre></div>
<p>is not productive when all elements of the input stream fail the predicate.
If you have a stream <code>s</code> of odd numbers and then <code>filter isEven s</code>, then <code>(filter isEven s) .head</code> will spin forever,
trying to find the first even number.</p>
<p>Productivity is undecidable, so productivity checking is always conservative.
The <code>--guardedness</code> option in the definition of <code>zipWith</code> enables a particular productivity checking heuristic for recursive functions.</p>
<p>I’ve found it quite easy to hit the limit of Agda’s productivity checker.
For example, it rejects this definition of the fibonacci sequence<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>, which (coming from a Haskell background) I consider an elegant and idiomatic use of streams:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>fib <span class="ot">:</span> Stream ℕ</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>head fib <span class="ot">=</span> <span class="dv">0</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>head <span class="ot">(</span>tail fib<span class="ot">)</span> <span class="ot">=</span> <span class="dv">1</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>tail <span class="ot">(</span>tail fib<span class="ot">)</span> <span class="ot">=</span> zipWith <span class="ot">_</span>+<span class="ot">_</span> fib <span class="ot">(</span>tail fib<span class="ot">)</span></span></code></pre></div>
<p>The limits of Agda’s productivity checking recently came up when I was working through
<a href="http://conal.net/papers/language-derivatives/">Symbolic and Automatic Differentiation of Languages by Conal Elliott</a>.
It defines a coinductive parser for context-free languages<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>, and some of the corecursive definitions are incorrectly rejected by the productivity checker.
Conal uses Agda’s <a href="https://agda.readthedocs.io/en/v2.7.0/language/sized-types.html">sized types</a> to fix this.
Sized types<a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a> are a type-based approach to termination and productivity checking,
and they seem to be the canonical move in this situation;
their section in the Agda manual uses the same kind of coinductive parser in its explanation of the feature.</p>
<p>Unfortunately Agda’s implementation of sized types is inconsistent<a href="#fn4" class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a>.
I’m not very comfortable using known inconsistent features because I don’t want the burden of figuring out whether I’m using them correctly.
When playing with infinite coinductive types like streams, I need the extra assurance that I’m not going to create an infinite loop or unsafe type cast.
I started playing with my own encoding of sized types under Agda’s <a href="https://agda.readthedocs.io/en/v2.7.0/language/safe-agda.html"><code>--safe</code> flag</a>,
which disables inconsistent features, and had some success.
Here’s what I found.</p>
<h2 id="the-encoding"><a href="#the-encoding">The encoding</a></h2>
<p>First we need propositional equality for
<a href="https://agda.readthedocs.io/en/v2.7.0/language/runtime-irrelevance.html">erased</a>
values, because I found erased size indices necessary for reasonable performance.</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="ot">_</span>≡<span class="ot">_</span> <span class="ot">{</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">}</span> <span class="ot">(@</span><span class="dv">0</span> x <span class="ot">:</span> A<span class="ot">)</span> <span class="ot">:</span> <span class="ot">@</span><span class="dv">0</span> A <span class="ot">→</span> <span class="dt">Set</span> <span class="kw">where</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>  refl <span class="ot">:</span> x ≡ x</span></code></pre></div>
<h3 id="example-streams"><a href="#example-streams">Example: streams</a></h3>
<p>Here’s how streams are defined:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> Stream <span class="ot">(</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">)</span> <span class="ot">(@</span><span class="dv">0</span> i <span class="ot">:</span> ℕ<span class="ot">)</span> <span class="ot">:</span> <span class="dt">Set</span> <span class="kw">where</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>  stream <span class="ot">:</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>    <span class="ot">({@</span><span class="dv">0</span> j <span class="ot">:</span> ℕ<span class="ot">}</span> <span class="ot">→</span> i ≡ suc j <span class="ot">→</span> A × Stream A j<span class="ot">)</span> <span class="ot">→</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>    Stream A i</span></code></pre></div>
<p>In words: a <code>Stream A i</code> is a function that returns a head <code>A</code> and a tail <code>Stream A j</code> whenever
you can show <code>i = j + 1</code>.</p>
<p>The destructors look like this:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>head <span class="ot">:</span> <span class="ot">{</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">}</span> <span class="ot">{@</span><span class="dv">0</span> i <span class="ot">:</span> ℕ<span class="ot">}</span> <span class="ot">→</span> Stream <span class="ot">(</span>suc i<span class="ot">)</span> A <span class="ot">→</span> A</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>head <span class="ot">(</span>stream s<span class="ot">)</span> <span class="ot">=</span> proj₁ <span class="ot">(</span>s refl<span class="ot">)</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>tail <span class="ot">:</span> <span class="ot">{</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">}</span> <span class="ot">{@</span><span class="dv">0</span> i <span class="ot">:</span> ℕ<span class="ot">}</span> <span class="ot">→</span> Stream <span class="ot">(</span>suc i<span class="ot">)</span> A <span class="ot">→</span> Stream i A</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>tail <span class="ot">(</span>stream s<span class="ot">)</span> <span class="ot">=</span> proj₂ <span class="ot">(</span>s refl<span class="ot">)</span></span></code></pre></div>
<p>The size parameter indicates how much of the stream is known to be usable (productive and consistent).
<code>head</code> says that a stream with at least one element can produce a head.
<code>tail</code> says that a stream with at least one element can produce a tail whose size is 1 smaller than the original.
A stream with size parameter 0 is unusable because <code>0 ≡ suc j</code> is false;
we have no information about the stream’s elements.</p>
<p>This is enough to define streams via recursive functions:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>map <span class="ot">:</span> <span class="ot">{</span>A B <span class="ot">:</span> <span class="dt">Set</span><span class="ot">}</span> <span class="ot">{@</span><span class="dv">0</span> i <span class="ot">:</span> ℕ<span class="ot">}</span> <span class="ot">→</span> <span class="ot">(</span>A <span class="ot">→</span> B<span class="ot">)</span> <span class="ot">→</span> Stream A i <span class="ot">→</span> Stream B i</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>map f s <span class="ot">=</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  stream <span class="ot">λ{</span> refl <span class="ot">→</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>    f <span class="ot">(</span>head s<span class="ot">)</span> , map f <span class="ot">(</span>tail s<span class="ot">)</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>  <span class="ot">}</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>zipWith <span class="ot">:</span> <span class="ot">{</span>A B C <span class="ot">:</span> <span class="dt">Set</span><span class="ot">}</span> <span class="ot">{@</span><span class="dv">0</span> i <span class="ot">:</span> ℕ<span class="ot">}</span> <span class="ot">→</span> <span class="ot">(</span>A <span class="ot">→</span> B <span class="ot">→</span> C<span class="ot">)</span> <span class="ot">→</span> Stream A i <span class="ot">→</span> Stream B i <span class="ot">→</span> Stream C i</span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>zipWith f s1 s2 <span class="ot">=</span></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a>  stream <span class="ot">λ{</span> refl <span class="ot">→</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>    f <span class="ot">(</span>head s1<span class="ot">)</span> <span class="ot">(</span>head s2<span class="ot">)</span> , zipWith f <span class="ot">(</span>tail s1<span class="ot">)</span> <span class="ot">(</span>tail s2<span class="ot">)</span></span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a>  <span class="ot">}</span></span></code></pre></div>
<p>I was excited to write the Haskell-style fibonacci sequence<a href="#fn5" class="footnote-ref" id="fnref5" role="doc-noteref"><sup>5</sup></a>:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>fib <span class="ot">:</span> <span class="ot">{@</span><span class="dv">0</span> i <span class="ot">:</span> ℕ<span class="ot">}</span> <span class="ot">→</span> Stream ℕ i</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>fib <span class="ot">=</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  stream <span class="ot">λ{</span> refl <span class="ot">→</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>    <span class="dv">0</span> , stream <span class="ot">λ{</span> refl <span class="ot">→</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>      <span class="dv">1</span> , zipWith <span class="ot">_</span>+<span class="ot">_</span> fib <span class="ot">(</span>tail fib<span class="ot">)</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>    <span class="ot">}</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>  <span class="ot">}</span></span></code></pre></div>
<p>Agda considers a function like <code>fib</code> total because the recursive calls are given a strictly smaller size parameter.
<code>fib</code> takes <code>i</code> as an implicit argument.
Inside the first <code>refl</code> case, <code>i</code> is refined to <code>suc j</code> for some <code>j</code>.
Then inside the second <code>refl</code> case, <code>j</code> is refined to <code>suc j'</code> so <code>i</code> is refined to <code>suc (suc j')</code> for some <code>j'</code>.
<code>zipWith _+_ fib (tail fib)</code> has type <code>Stream ℕ j'</code>, and size indices are passed implicitly as follows:
<code>zipWith _+_ (fib {i = j'}) (tail (fib {i = suc j'}))</code>.
Agda sees this is
<a href="https://agda.readthedocs.io/en/v2.7.0/language/termination-checking.html#structural-recursion">structural recursion</a>—each recursive <code>fib</code> call is given a strictly smaller size—and accepts the definition as terminating.</p>
<p>Streams can also have more complex sizes.
The following function averages each consecutive pair of elements,
and the sizes say that for every element in the output stream, two elements are required from the input stream:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>fil <span class="ot">:</span> <span class="ot">{@</span><span class="dv">0</span> i <span class="ot">:</span> ℕ<span class="ot">}</span> <span class="ot">→</span> Stream ℕ <span class="ot">(</span>i * <span class="dv">2</span><span class="ot">)</span> <span class="ot">→</span> Stream ℕ i</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>fil s <span class="ot">=</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  stream <span class="ot">λ{</span> refl <span class="ot">→</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>    avg <span class="ot">(</span>head s<span class="ot">)</span> <span class="ot">(</span>head <span class="ot">(</span>tail s<span class="ot">))</span> , fil <span class="ot">(</span>tail <span class="ot">(</span>tail s<span class="ot">))</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>  <span class="ot">}</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>    avg <span class="ot">:</span> ℕ <span class="ot">→</span> ℕ <span class="ot">→</span> ℕ</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>    avg m n <span class="ot">=</span> <span class="ot">(</span>m + n<span class="ot">)</span> / <span class="dv">2</span></span></code></pre></div>
<p>The size parameter of a stream can also be “forgotten”, for situations where sizes don’t matter:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> Stream-∞ <span class="ot">(</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">)</span> <span class="ot">:</span> <span class="dt">Set</span> <span class="kw">where</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>  stream-∞ <span class="ot">:</span> <span class="ot">({@</span><span class="dv">0</span> i <span class="ot">:</span> ℕ<span class="ot">}</span> <span class="ot">→</span> Stream A i<span class="ot">)</span> <span class="ot">→</span> Stream-∞ A</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>to-∞ <span class="ot">:</span> <span class="ot">{</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">}</span> <span class="ot">→</span> <span class="ot">({@</span><span class="dv">0</span> i <span class="ot">:</span> ℕ<span class="ot">}</span> <span class="ot">→</span> Stream A i<span class="ot">)</span> <span class="ot">→</span> Stream-∞ A</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>to-∞ <span class="ot">=</span> stream-∞</span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>from-∞ <span class="ot">:</span> <span class="ot">{</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">}</span> <span class="ot">→</span> Stream-∞ A <span class="ot">→</span> <span class="ot">({@</span><span class="dv">0</span> i <span class="ot">:</span> ℕ<span class="ot">}</span> <span class="ot">→</span> Stream A i<span class="ot">)</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>from-∞ <span class="ot">(</span>stream-∞ f<span class="ot">)</span> <span class="ot">=</span> f</span></code></pre></div>
<p><code>Stream-∞</code> is the typical coinductive stream type, equivalent to the coinductive definition I gave at the start of this post.
Such a stream is unboundedly usable; you can always get its head or tail:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>head-∞ <span class="ot">:</span> <span class="ot">{</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">}</span> <span class="ot">→</span> Stream-∞ A <span class="ot">→</span> A</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>head-∞ s <span class="ot">=</span> head <span class="ot">(</span>from-∞ s <span class="ot">{</span>i <span class="ot">=</span> <span class="dv">1</span><span class="ot">})</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>tail-∞ <span class="ot">:</span> <span class="ot">{</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">}</span> <span class="ot">→</span> Stream-∞ A <span class="ot">→</span> Stream-∞ A</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>tail-∞ s <span class="ot">=</span> to-∞ <span class="ot">(</span>tail <span class="ot">(</span>from-∞ s<span class="ot">))</span></span></code></pre></div>
<p>A program that consumes an entire <code>Stream-∞</code> is productive but non-terminating.
Non-termination isn’t useful for theorem proving, so it’s usually avoided in Agda, but it is useful for everyday programs.
The <a href="https://en.wikipedia.org/wiki/Yes_(Unix)"><code>yes</code></a> command is a reasonable non-terminating program, and so is a program that prints the fibonacci sequence.
Here’s one way to consume infinite streams that I consider morally okay, despite requiring unsafe Agda<a href="#fn6" class="footnote-ref" id="fnref6" role="doc-noteref"><sup>6</sup></a>:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">postulate</span> <span class="ot">_</span>*&gt;<span class="ot">_</span> <span class="ot">:</span> <span class="ot">{</span>A B <span class="ot">:</span> <span class="dt">Set</span><span class="ot">}</span> <span class="ot">→</span> IO A <span class="ot">→</span> IO B <span class="ot">→</span> IO B</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="pp">{-# COMPILE GHC _*&gt;_ = \_ _ -&gt; (*&gt;) #-}</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a><span class="pp">{-# NON_TERMINATING #-}</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>consume-∞ <span class="ot">:</span> <span class="ot">{</span>A B <span class="ot">:</span> <span class="dt">Set</span><span class="ot">}</span> <span class="ot">→</span> <span class="ot">(</span>A <span class="ot">→</span> IO ⊤<span class="ot">)</span> <span class="ot">→</span> Stream-∞ A <span class="ot">→</span> IO B</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>consume-∞ f s <span class="ot">=</span> f <span class="ot">(</span>head-∞ s<span class="ot">)</span> *&gt; consume-∞ f <span class="ot">(</span>tail-∞ s<span class="ot">)</span></span></code></pre></div>
<p><code>consume-∞</code> is a loop that <a href="http://conal.net/blog/posts/is-haskell-a-purely-functional-language">arbitrarily</a> observes each stream element in turn.
Its output type is <code>IO B</code> for all types <code>B</code> because it never returns.</p>
<p>This can be used to print the fibonacci sequence:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>main <span class="ot">:</span> IO ⊤</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> consume-∞ putStrLn <span class="ot">(</span>to-∞ <span class="ot">(</span>map show-ℕ fib<span class="ot">))</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">open</span> <span class="kw">import</span> Data<span class="ot">.</span>Nat<span class="ot">.</span>Show <span class="kw">renaming</span> <span class="ot">(</span>show <span class="kw">to</span> show-ℕ<span class="ot">)</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">postulate</span> putStrLn <span class="ot">:</span> String <span class="ot">→</span> IO ⊤</span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>    <span class="pp">{-# FOREIGN GHC import qualified Data.Text.IO #-}</span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>    <span class="pp">{-# COMPILE GHC putStrLn = Data.Text.IO.putStrLn #-}</span></span></code></pre></div>
<pre><code>$ ./fib | head -n 10
0
1
1
2
3
5
8
13
21
34

$ ./fib | head -n 1000 | tail -n 1
26863810024485359386146727202142923967616609318986952340123175997617981700247881689338369654483356564191827856161443356312976673642210350324634850410377680367334151172899169723197082763985615764450078474174626</code></pre>
<h3 id="example-colists"><a href="#example-colists">Example: (co)lists</a></h3>
<p>Here’s a brief second example so you can start to extrapolate.
<code>Colist</code> is the coinductive list; an <code>A</code>-producing process that could end, but might also continue forever:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> Colist <span class="ot">(</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">)</span> <span class="ot">(@</span><span class="dv">0</span> i <span class="ot">:</span> ℕ<span class="ot">)</span> <span class="ot">:</span> <span class="dt">Set</span> <span class="kw">where</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>  colist <span class="ot">:</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>    <span class="ot">({@</span><span class="dv">0</span> j <span class="ot">:</span> ℕ<span class="ot">}</span> <span class="ot">→</span> i ≡ suc j <span class="ot">→</span> Maybe <span class="ot">(</span>A × Colist A j<span class="ot">))</span> <span class="ot">→</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>    Colist A i</span></code></pre></div>
<h3 id="summary"><a href="#summary">Summary</a></h3>
<p>In short: a datatype definition is given a size parameter, and recursive uses of the type are “guarded” by a proof that the size parameter decreases.</p>
<p>In the
<a href="https://github.com/LightAndLight/agda-safe-sized-types">actual code</a>
I’ve packaged this pattern as its own type <code>■ : (A : @0 ℕ → Set) → @0 ℕ → Set</code>, so <code>Stream</code> and <code>Colist</code> become:</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> Stream <span class="ot">(</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">)</span> <span class="ot">(@</span><span class="dv">0</span> i <span class="ot">:</span> ℕ<span class="ot">)</span> <span class="ot">:</span> <span class="dt">Set</span> <span class="kw">where</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>  stream <span class="ot">:</span> ■ <span class="ot">(λ</span> j <span class="ot">→</span> A × Stream A j<span class="ot">)</span> i <span class="ot">→</span> Stream A i</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> Colist <span class="ot">(</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">)</span> <span class="ot">(@</span><span class="dv">0</span> i <span class="ot">:</span> ℕ<span class="ot">)</span> <span class="ot">:</span> <span class="dt">Set</span> <span class="kw">where</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>  colist <span class="ot">:</span> ■ <span class="ot">(λ</span> j <span class="ot">→</span> Maybe <span class="ot">(</span>A × Colist A j<span class="ot">))</span> i <span class="ot">→</span> Colist A i</span></code></pre></div>
<h2 id="proof"><a href="#proof">Proof</a></h2>
<p><code>Stream-∞</code> is clearly a coinductive stream, but I still had my doubts about <code>Stream</code>.
The definitive test is whether it obeys <a href="https://en.wikipedia.org/wiki/Coinduction#Relationship_with_F-coalgebras">coalgebraic semantics</a>.
I was able to prove that <code>Stream</code> is the final coalgebra of a particular functor, in the category of size-indexed families of types.
The functor in question is like the one that gives rise to unsized streams (<code>F(X) = A * X</code>), but it also keeps track of the change in size indices.</p>
<p>The proofs are not very fun to read, so I’ll omit them from this post.
You can find them
<a href="https://github.com/LightAndLight/agda-safe-sized-types/blob/8876b3de679618d352481a69e2e1b8ed48b460e6/src/Codata/SafeSized/Stream/Coalgebra.agda#L141-L243">here</a>.</p>
<h2 id="future-work"><a href="#future-work">Future work</a></h2>
<ul>
<li><p>Parser combinators</p>
<p>This all started because I wanted to figure out how to do parsing in Agda.
I successfully used this style of sized coinductive types to write a coinductive parser.
It was easy to write the connectives for parsing regular languages, as in Conal’s paper.
I then added a guarded fixpoint combinator to parse non-regular languages, like expression trees.
I’ve now got a total, <code>--safe</code> parser combinator library for Agda, which I’ll introduce in another post.</p></li>
<li><p>Generalised greatest fixed point proofs</p>
<p>I proved that <code>Stream</code> was a final coalgebra, but I have no proofs for any other codatatypes.
I’m confident that I could write them, but it would be a chore.
Is it possible to validate the approach once and for all for the greatest fixed point <code>ν : ((@0 ℕ → Set) → @0 ℕ → Set) → @0 ℕ → Set</code>?
Then, justifying a particular codatatype definition would be as simple as defining an isomorphism with <code>ν F</code> for a particular <code>F</code>.</p></li>
<li><p>Where’s the limit?</p>
<p>I’m curious about the limitations of my approach.
It’s good enough for the practical coinductive problems I’ve tested it on, so where does it break down?
Consistency often comes at the expense of completeness.
Does this technique rule out some sound programs that Agda’s normal sized types can encode?</p></li>
</ul>
<h2 id="appendix-philosophical-ramblings"><a href="#appendix-philosophical-ramblings">Appendix: philosophical ramblings</a></h2>
<h3 id="infinity-as-an-object"><a href="#infinity-as-an-object">Infinity as an object</a></h3>
<p>The original sized types paper (Hughes &amp; Pareto, 1996) and Agda’s implementation of sized types both introduce an explicit size for unbounded usability;
called <code>ω</code> and <code>∞</code> respectively.
I’m suspicious of this move, because it feels like it’s begging for paradoxes<a href="#fn7" class="footnote-ref" id="fnref7" role="doc-noteref"><sup>7</sup></a>.</p>
<p>The sized types paper is very careful about uses of <code>ω</code>, noting that for types <code>∀(i : Size). T</code> it’s not always sound
to instantiate <code>i</code> with <code>ω</code> in <code>T</code>.
The resulting type system is more complex and harder to implement correctly,
and I doubt that the convenience is worth it.</p>
<p>I think my intuitions here are justified given the state of Agda’s built-in sized types.
Agda has an issue label called <a href="https://github.com/agda/agda/labels/infinity-less-than-infinity">infinity-less-than-infinity</a>,
because there are a number of ways to prove <code>false</code> by assuming that the size <code>∞</code> is smaller than itself.
Whether this is due to software bugs or broken theory,
I think the root cause is the complexity of trying to think of infinity as “the same sort of thing” as a finite size.</p>
<h3 id="codata-via-pi-types"><a href="#codata-via-pi-types">Codata via <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Π</mi><annotation encoding="application/x-tex">\Pi</annotation></semantics></math>-types</a></h3>
<p>I like this encoding of sized types because it puts a <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Π</mi><annotation encoding="application/x-tex">\Pi</annotation></semantics></math>-type at the center of the coinductive definition.
It could be made even more obvious like this:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> Field <span class="ot">:</span> <span class="dt">Set</span> <span class="kw">where</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>  head tail <span class="ot">:</span> Field</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> Stream <span class="ot">(</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">)</span> <span class="ot">(@</span><span class="dv">0</span> i <span class="ot">:</span> ℕ<span class="ot">)</span> <span class="ot">:</span> <span class="dt">Set</span> <span class="kw">where</span></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>  stream <span class="ot">:</span></span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a>    <span class="ot">({@</span><span class="dv">0</span> j <span class="ot">:</span> ℕ<span class="ot">}</span> <span class="ot">→</span> i ≡ suc j <span class="ot">→</span> <span class="ot">(</span>f <span class="ot">:</span> Field<span class="ot">)</span> <span class="ot">→</span> case f of <span class="ot">λ{</span></span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a>      head <span class="ot">→</span> A <span class="ot">;</span></span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a>      tail <span class="ot">→</span> Stream A j</span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a>    <span class="ot">})</span> <span class="ot">→</span></span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a>    Stream A i</span></code></pre></div>
<p>Then defining a stream by cases on <code>Field</code> is pretty close to copattern matching:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a>repeat <span class="ot">:</span> <span class="ot">{</span>A <span class="ot">:</span> <span class="dt">Set</span><span class="ot">}</span> <span class="ot">{@</span><span class="dv">0</span> i <span class="ot">:</span> ℕ<span class="ot">}</span> <span class="ot">→</span> A <span class="ot">→</span> Stream A i</span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>repeat x <span class="ot">=</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>  stream <span class="ot">λ{</span> refl <span class="ot">→</span></span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a>    <span class="ot">λ{</span></span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>      head <span class="ot">→</span> x <span class="ot">;</span></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a>      tail <span class="ot">→</span> repeat x</span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a>    <span class="ot">}</span></span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a>  <span class="ot">}</span></span></code></pre></div>
<p>The relationship between data and codata seems analogous to the relationship between <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Σ</mi><annotation encoding="application/x-tex">\Sigma</annotation></semantics></math>-types and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Π</mi><annotation encoding="application/x-tex">\Pi</annotation></semantics></math>-types.
I don’t have anything rigorous to say about this; it’s just a feeling.
Here’s a table that expands on the feeling:</p>
<style>
.padded-columns tr > td + td {
  padding-left: 2em;
}
</style>
<table class="padded-columns" align="center">
<tbody>
<tr>
<td>
Data
</td>
<td>
Codata
</td>
</tr>
<tr>
<td>
Induction
</td>
<td>
Coinduction
</td>
</tr>
<tr>
<td>
Positive types
</td>
<td>
Negative types
</td>
</tr>
<tr>
<td>
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Σ</mi><annotation encoding="application/x-tex">\Sigma</annotation></semantics></math>-types
</td>
<td>
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Π</mi><annotation encoding="application/x-tex">\Pi</annotation></semantics></math>-types
</td>
</tr>
<tr>
<td>
Intensional equality
</td>
<td>
Extensional equality
</td>
</tr>
</tbody>
</table>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Here’s a version that works:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode agda"><code class="sourceCode agda"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>fib <span class="ot">:</span> Stream ℕ</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>fib <span class="ot">=</span> fib&#39; <span class="dv">0</span> <span class="dv">1</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>    fib&#39; <span class="ot">:</span> ℕ <span class="ot">→</span> ℕ <span class="ot">→</span> Stream ℕ</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    head <span class="ot">(</span>fib&#39; a b<span class="ot">)</span> <span class="ot">=</span> a</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    tail <span class="ot">(</span>fib&#39; a b<span class="ot">)</span> <span class="ot">=</span> fib&#39; b <span class="ot">(</span>a + b<span class="ot">)</span></span></code></pre></div>
<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></li>
<li id="fn2"><p>See also:</p>
<ul>
<li><p>Hasuo, I., &amp; Jacobs, B. (2005, September).
Context-free languages via coalgebraic trace semantics.
In International Conference on Algebra and Coalgebra in Computer Science (pp. 213-231). Berlin, Heidelberg: Springer Berlin Heidelberg.</p></li>
<li><p>Winter, J., Bonsangue, M. M., &amp; Rutten, J. (2011, August).
Context-free languages, coalgebraically.
In International Conference on Algebra and Coalgebra in Computer Science (pp. 359-376). Berlin, Heidelberg: Springer Berlin Heidelberg.</p></li>
<li><p>Abel, A. (2016).
Equational reasoning about formal languages in coalgebraic style.
preprint available at http://www.cse.chalmers.se/~abela/jlamp17.pdf.</p></li>
</ul>
<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></li>
<li id="fn3"><p>See:</p>
<ul>
<li><p>Hughes, J., Pareto, L., &amp; Sabry, A. (1996, January).
Proving the correctness of reactive systems using sized types. In Proceedings of the 23rd ACM SIGPLAN-SIGACT symposium on Principles of programming languages (pp. 410-423).</p></li>
<li><p>Abel, A. (2008). Semi-continuous sized types and termination. Logical methods in computer science, 4.</p></li>
</ul>
<a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></li>
<li id="fn4"><p>See:</p>
<ul>
<li>Relevant GitHub activity: <a href="https://github.com/agda/agda/pull/5354" class="uri">https://github.com/agda/agda/pull/5354</a>
<ul>
<li><a href="https://github.com/agda/agda/issues/1201" class="uri">https://github.com/agda/agda/issues/1201</a></li>
<li><a href="https://github.com/agda/agda/issues/1946" class="uri">https://github.com/agda/agda/issues/1946</a></li>
<li><a href="https://github.com/agda/agda/issues/2820" class="uri">https://github.com/agda/agda/issues/2820</a></li>
<li><a href="https://github.com/agda/agda/issues/3026" class="uri">https://github.com/agda/agda/issues/3026</a></li>
</ul></li>
<li><a href="https://ionathan.ch/2021/08/04/sized-types.html">The State of Sized Types (2021)</a></li>
</ul>
<a href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></li>
<li id="fn5"><p>In Haskell: <code>fib = 0 : 1 : zipWith (+) fib (tail fib)</code><a href="#fnref5" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn6"><p>In the real code I defined this in a separate file so that I can use <code>--safe</code> everywhere else.<a href="#fnref6" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn7"><p><a href="https://ncatlab.org/nlab/show/HomePage">nLab</a> redirects Girard’s paradox to <a href="https://ncatlab.org/nlab/show/Burali-Forti%27s+paradox">Burali-Forti’s paradox</a>,
which describes a paradox using ordinal numbers which has a very similar vibe to Agda’s sized types situation.<a href="#fnref7" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
    ]]></content>
    
</entry>
<entry>
    <title>Per-project Nix substituters</title>
    <link href="https://blog.ielliott.io/per-project-nix-substituters" />
    
    <id>https://blog.ielliott.io/per-project-nix-substituters</id>
    
    <published>2024-08-10T00:00:00Z</published>
    <updated>2024-08-10T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/per-project-nix-substituters"><![CDATA[<p>A lot of Nix projects end up with their own binary cache (also known as a “substituter”).
Nix can be quite slow when it’s configured to use many project-specific substituters,
because it queries them all when checking if it needs to build a derivation. In a specific
project, most of the other substituters Nix knows about are irrelevant, and querying them
is wasted effort. My solution is to only enable <a href="https://cache.nixos.org" class="uri">https://cache.nixos.org</a> globally, and
to selectively enable other substituters while I’m working on a project that needs them.
Here’s how I do it.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/per-project-nix-substituters"><![CDATA[
      
      <div id="toc">
<h3>Contents</h3>
<ul>
<li><a href="#setup">Setup</a></li>
<li><a href="#without-flakes">Without Flakes</a></li>
<li><a href="#with-flakes">With Flakes</a></li>
</ul>
</div>
<p>A lot of Nix projects end up with their own binary cache (also known as a “substituter”).
Nix can be quite slow when it’s configured to use many project-specific substituters<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>,
because it queries them all when checking if it needs to build a derivation. In a specific
project, most of the other substituters Nix knows about are irrelevant, and querying them
is wasted effort. My solution is to only enable <a href="https://cache.nixos.org" class="uri">https://cache.nixos.org</a> globally, and
to selectively enable other substituters while I’m working on a project that needs them.
Here’s how I do it.</p>
<h2 id="setup"><a href="#setup">Setup</a></h2>
<p>In <code>configuration.nix</code>, set the system’s trusted substituters<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>nix<span class="op">.</span>settings<span class="op">.</span>trusted<span class="op">-</span>substituters = <span class="op">[</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;https://cache.nixos.org/&quot;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;substituter-1&quot;</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;substituter-2&quot;</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;...&quot;</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;substituter-N&quot;</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="op">]</span>;</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>nix<span class="op">.</span>settings<span class="op">.</span>trusted<span class="op">-</span>public<span class="op">-</span>keys = <span class="op">[</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=&quot;</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;other-public-key-1&quot;</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;other-public-key-2&quot;</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;...&quot;</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;other-public-key-N&quot;</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="op">]</span>;</span></code></pre></div>
<p>And set Nix’s default substituter:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>nix<span class="op">.</span>settings<span class="op">.</span>substituters = <span class="op">[</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;https://cache.nixos.org/&quot;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="op">]</span>;</span></code></pre></div>
<p>By default, only the substituters in <code>substituters</code> will be used by Nix.
<code>trusted-substituters</code> lists the substituters that regular users are allowed to use in Nix builds.</p>
<h2 id="without-flakes"><a href="#without-flakes">Without Flakes</a></h2>
<p>To enable other substituters, use the <code>NIX_CONFIG</code> environment variable
with the <code>extra-substituters</code><a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a><sup>,</sup><a href="#fn4" class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a> setting:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="bu">export</span> <span class="va">NIX_CONFIG</span><span class="op">=</span><span class="st">&quot;extra-substituters = substituter-42&quot;</span></span></code></pre></div>
<p>Or use <code>substituters</code> to override the system’s substituters:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="bu">export</span> <span class="va">NIX_CONFIG</span><span class="op">=</span><span class="st">&quot;substituters = substituter-42&quot;</span></span></code></pre></div>
<p>If the substituters named in these local settings aren’t defined in the <code>trusted-substituters</code>
system setting,
then Nix will ignore them and print the following message:</p>
<pre><code>warning: ignoring untrusted substituter &#39;{substituter URL}&#39;, you are not a trusted user.</code></pre>
<p>I use <a href="https://direnv.net/">direnv</a> to automatically set and unset <code>NIX_CONFIG</code> by putting the <code>export NIX_CONFIG=...</code>
command inside a <code>.envrc</code> in the project root.</p>
<h2 id="with-flakes"><a href="#with-flakes">With Flakes</a></h2>
<p>The <code>nixConfig</code> attribute can be used to set Nix configuration from inside a Flake<a href="#fn5" class="footnote-ref" id="fnref5" role="doc-noteref"><sup>5</sup></a>:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>  <span class="va">nixConfig</span>.<span class="va">extra-substituters</span> <span class="op">=</span> <span class="op">[</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>    <span class="st">&quot;substituter-42&quot;</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">];</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>  <span class="va">inputs</span> <span class="op">=</span> <span class="op">.</span>..;</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>  outputs = <span class="op">.</span>..;</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>By default, Nix will ask for permission to use the config specified by the Flake.
I use <a href="https://github.com/nix-community/nix-direnv">nix-direnv</a> to automatically load and unload <a href="https://nix.dev/manual/nix/2.18/command-ref/new-cli/nix3-develop">Nix develop shells</a> when switching projects,
and the permission prompt <a href="https://github.com/direnv/direnv/issues/1022">breaks direnv on my shell</a>.</p>
<p>To work around this, I enable the <a href="https://nix.dev/manual/nix/2.18/command-ref/conf-file#conf-accept-flake-config"><code>accept-flake-config</code></a> Nix option in my <code>configuration.nix</code>:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>nix<span class="op">.</span>extraOptions = <span class="st">&#39;&#39;</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="st">  experimental-features = nix-command flakes</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="st">  accept-flake-config = true</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="st">&#39;&#39;</span>;</span></code></pre></div>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Some relevant discussions:</p>
<ul>
<li><a href="https://discourse.nixos.org/t/a-common-public-nix-cache/26998#many-caches-are-bad-2" class="uri">https://discourse.nixos.org/t/a-common-public-nix-cache/26998#many-caches-are-bad-2</a></li>
<li><a href="https://github.com/NixOS/nix/issues/3019" class="uri">https://github.com/NixOS/nix/issues/3019</a></li>
</ul>
<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></li>
<li id="fn2"><p><a href="https://nix.dev/manual/nix/2.18/command-ref/conf-file#conf-trusted-substituters"><code>trusted-substituters</code> — <code>nix.conf</code> reference</a><a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><blockquote>
<p>A configuration setting usually overrides any previous value.
However, for settings that take a list of items, you can prefix the name of the setting
by <code>extra-</code> to append to the previous value.</p>
<p>— <a href="https://nix.dev/manual/nix/2.18/command-ref/conf-file#file-format"><code>nix.conf</code> reference</a></p>
</blockquote>
<a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></li>
<li id="fn4"><p><a href="https://nix.dev/manual/nix/2.18/command-ref/conf-file#conf-substituters"><code>substituters</code> — <code>nix.conf</code> reference</a><a href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>See <code>nixConfig</code> in <a href="https://nix.dev/manual/nix/2.18/command-ref/new-cli/nix3-flake.html#flake-format%3E">Flake format — Nix Flake reference</a><a href="#fnref5" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
    ]]></content>
    
</entry>
<entry>
    <title>Troubleshooting LightDM's test mode</title>
    <link href="https://blog.ielliott.io/troubleshooting-lightdms-test-mode" />
    
    <id>https://blog.ielliott.io/troubleshooting-lightdms-test-mode</id>
    
    <published>2024-08-03T00:00:00Z</published>
    <updated>2024-08-03T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/troubleshooting-lightdms-test-mode"><![CDATA[<p>Recently I’ve been tweaking the appearance of <a href="https://github.com/LightAndLight/personal-configs">my desktop environment</a>,
which consists of <a href="https://xmonad.org/">XMonad</a> and <a href="https://github.com/taffybar/taffybar">Taffybar</a>,
with <a href="https://github.com/canonical/lightdm">LightDM</a> as the display manager,
all tied together using <a href="https://nixos.org/">NixOS</a> and <a href="https://github.com/nix-community/home-manager">home-manager</a>.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/troubleshooting-lightdms-test-mode"><![CDATA[
      
      <div id="toc">
<h3>Contents</h3>
<ul>
<li><a href="#summary">Summary</a>
<ul>
<li><a href="#symptoms">Symptoms</a></li>
<li><a href="#solution">Solution</a></li>
</ul></li>
<li><a href="#details">Details</a></li>
</ul>
</div>
<p>Recently I’ve been tweaking the appearance of <a href="https://github.com/LightAndLight/personal-configs">my desktop environment</a>,
which consists of <a href="https://xmonad.org/">XMonad</a> and <a href="https://github.com/taffybar/taffybar">Taffybar</a>,
with <a href="https://github.com/canonical/lightdm">LightDM</a> as the display manager,
all tied together using <a href="https://nixos.org/">NixOS</a> and <a href="https://github.com/nix-community/home-manager">home-manager</a>.</p>
<p>Taffybar was very easy to customise because it uses a single CSS file.
XMonad was also not too bad, but needs a custom <a href="https://wiki.archlinux.org/title/Xorg#Composite">X compositor</a> to get really nice results (I’m using <a href="https://github.com/yshui/picom">picom</a>).
LightDM is the last thing on my list.</p>
<p>If I’m going to be tweaking my <a href="https://wiki.archlinux.org/title/LightDM#Greeter">greeter</a>’s appearance,
I don’t want to repeatedly log in and out to test it.
I’d like to preview the changes in a window while I’ve got my editor open in another.</p>
<p><a href="https://wiki.archlinux.org/title/LightDM#Testing">LightDM on ArchWiki</a> says to run <code>lightdm --test-mode</code>, but this didn’t work for me.</p>
<h2 id="summary"><a href="#summary">Summary</a></h2>
<h3 id="symptoms"><a href="#symptoms">Symptoms</a></h3>
<ul>
<li><p><code>lightdm --test-mode --debug</code> failed</p>
<ul>
<li>Greeter logs (<code>.cache/lightdm/log/seat0-greeter.log</code>) show <code>Failed to open PAM session: Authentication failure</code></li>
</ul></li>
<li><p><code>sudo -u lightdm lightdm --test-mode --debug</code> reports <code>Failed to get D-Bus connection</code></p>
<ul>
<li><p>X logs (<code>/var/lib/lightdm/.cache/lightdm/log/x-1.log</code>) contain</p>
<pre><code>Authorization required, but no authorization protocol specified


Xephyr cannot open host display. Is DISPLAY set?</code></pre></li>
</ul></li>
</ul>
<h3 id="solution"><a href="#solution">Solution</a></h3>
<p>Run <code>xhost +SI:localuser:lightdm</code> to allow the <code>lightdm</code> user to connect to the X user,
then run <code>sudo -u lightdm lightdm --test-mode</code>.</p>
<h2 id="details"><a href="#details">Details</a></h2>
<p>When I ran <code>lightdm --test-mode</code> a small black window briefly appeared and then the program exited with status 1.
I added the <code>--debug</code> flag, and saw that a subprocess had failed:</p>
<pre><code>$ lightdm --test-mode --debug
...
[+0.07s] DEBUG: Session pid=29039: Started with service &#39;lightdm-greeter&#39;, username &#39;{my username}&#39;
[+0.08s] DEBUG: Session pid=29039: Authentication complete with return value 0: Success
[+0.08s] DEBUG: Seat seat0: Session authenticated, running command
[+0.08s] DEBUG: Session pid=29039: Not setting XDG_VTNR
[+0.08s] DEBUG: Session pid=29039: Running command /nix/store/ikwkdnyzd8xflr3j7cabmy6vr3srvp3j-lightdm-gtk-greeter-2.0.8/bin/lightdm-gtk-greeter
[+0.08s] DEBUG: Creating shared data directory /var/lib/lightdm-data/{my username}
[+0.08s] WARNING: Could not create user data directory /var/lib/lightdm-data/{my username}: Error creating directory /var/lib/lightdm-data/{my username}: Permission denied
[+0.08s] DEBUG: Session pid=29039: Logging to /home/{my username}/.cache/lightdm/log/seat0-greeter.log
[+0.08s] DEBUG: Greeter closed communication channel
[+0.08s] DEBUG: Session pid=29039: Exited with return value 1
...</code></pre>
<p>The output also told me where the subprocess stored its logs, so I checked there:</p>
<pre><code>$ cat /home/{my username}/.cache/lightdm/log/seat0-greeter.log
Failed to open PAM session: Authentication failure</code></pre>
<p>A <a href="https://en.wikipedia.org/wiki/Linux_PAM">PAM</a> error.</p>
<p><code>man pam</code> says that PAM errors are often logged to <code>syslog</code>, so I checked the <a href="https://wiki.archlinux.org/title/Systemd/Journal">systemd journal</a>:</p>
<pre><code>$ journalctl --user -b -r -g pam -n 10
Aug 03 11:22:44 {my hostname} lightdm[29039]: pam_systemd(lightdm-greeter:session): Failed to create session: Access denied
Aug 03 11:22:44 {my hostname} lightdm[29039]: pam_succeed_if(lightdm-greeter:session): requirement &quot;user = lightdm&quot; not met by user &quot;{my username}&quot;
...</code></pre>
<p>It seems that LightDM doesn’t like being run as a normal user, and would rather be run as the <code>lightdm</code> user.
I found that the LightDM README actually has <a href="https://github.com/canonical/lightdm?tab=readme-ov-file#display-setup-script">a note</a> about using <code>sudo -u lightdm</code> for <code>--test-mode</code>,
so I tried it:</p>
<pre><code>$ sudo -u lightdm lightdm --test-mode --debug
[+0.00s] DEBUG: Logging to /var/lib/lightdm/.cache/lightdm/log/lightdm.log
[+0.00s] DEBUG: Starting Light Display Manager 1.32.0, UID=78 PID=30100
...
[+0.00s] DEBUG: Loading configuration from /etc/lightdm/lightdm.conf
[+0.00s] DEBUG: Running in user mode
[+0.00s] DEBUG: Using Xephyr for X servers
...
[+0.00s] DEBUG: Using D-Bus name org.freedesktop.DisplayManager
...
[+0.00s] DEBUG: Seat seat0: Starting
[+0.00s] DEBUG: Seat seat0: Creating greeter session
[+0.00s] DEBUG: Loading users from org.freedesktop.Accounts
[+0.00s] DEBUG: Seat seat0: Creating display server of type x
[+0.00s] DEBUG: Seat seat0: Starting local X display
[+0.01s] DEBUG: XServer 1: Logging to /var/lib/lightdm/.cache/lightdm/log/x-1.log
[+0.01s] DEBUG: XServer 1: Writing X server authority to /var/lib/lightdm/.cache/lightdm/run/root/:1
[+0.01s] DEBUG: XServer 1: Launching X Server
[+0.01s] DEBUG: Launching process 30107: /run/current-system/sw/bin/Xephyr :1 -seat seat0 -auth /var/lib/lightdm/.cache/lightdm/run/root/:1 -nolisten tcp
[+0.01s] DEBUG: XServer 1: Waiting for ready signal from X server :1
Failed to get D-Bus connection</code></pre>
<p>That didn’t work either.
I checked the X server logs that were generated:</p>
<pre><code>$ sudo cat /var/lib/lightdm/.cache/lightdm/log/x-1.log
Authorization required, but no authorization protocol specified


Xephyr cannot open host display. Is DISPLAY set?</code></pre>
<p>I didn’t undertand what this meant. Is <code>DISPLAY</code> set?</p>
<pre><code>$ sudo -u lightdm env | rg DISPLAY
DISPLAY=:0</code></pre>
<p>It is. I was stumped.</p>
<p>After lots of searching and browsing,
a <a href="https://kagi.com">Kagi search</a> for <code>lightdm --test-mode</code> turned up <a href="https://forums.raspberrypi.com/viewtopic.php?t=220324">Problems with lightdm test mode - Raspberry Pi Forums</a>,
which lead to <a href="https://ubuntuhandbook.org/index.php/2014/05/capture-your-lightdm-login-screen-in-ubuntu-14-04/">Capture Your LightDM Login Screen in Ubuntu Unity | UbuntuHandbook</a>,
which uses a variation of <code>sudo -u lightdm lightdm --test-mode</code>
after calling <code>xhost +SI:localuser:lightdm</code>.</p>
<p><code>man xhost</code> says:</p>
<blockquote>
<p>The xhost program is used to add and delete host names or user names to the list allowed to make connections to the X server.
In the case of hosts, this provides a rudimentary form of privacy control and security.
It is only sufficient for a workstation (single user) environment, although it does limit the worst abuses.
Environments which require more sophisticated measures should implement the user-based mechanism or use the hooks in the protocol for passing other authentication data to the server.</p>
</blockquote>
<p>That seemed promising.</p>
<pre><code>$ xhost +SI:localuser:lightdm
localuser:lightdm being added to access control list</code></pre>
<p>Running LightDM again worked!</p>
<pre><code>$ sudo -u lightdm lightdm --test-mode --debug
...
[+0.09s] DEBUG: Session pid=40112: Started with service &#39;lightdm-greeter&#39;, username &#39;lightdm&#39;
[+0.09s] DEBUG: Session pid=40112: Authentication complete with return value 0: Success
[+0.09s] DEBUG: Seat seat0: Session authenticated, running command
[+0.09s] DEBUG: Session pid=40112: Not setting XDG_VTNR
[+0.09s] DEBUG: Session pid=40112: Running command /nix/store/ikwkdnyzd8xflr3j7cabmy6vr3srvp3j-lightdm-gtk-greeter-2.0.8/bin/lightdm-gtk-greeter
[+0.09s] DEBUG: Creating shared data directory /var/lib/lightdm-data/lightdm
[+0.09s] DEBUG: Session pid=40112: Logging to /var/lib/lightdm/.cache/lightdm/log/seat0-greeter.log
[+0.16s] DEBUG: Greeter connected version=1.32.0 api=1 resettable=false
[+0.35s] DEBUG: Greeter start authentication
[+0.35s] DEBUG: Session: Not setting XDG_VTNR
[+0.35s] DEBUG: Session pid=40144: Started with service &#39;lightdm&#39;, username &#39;(null)&#39;
[+0.35s] DEBUG: Session pid=40144: Got 1 message(s) from PAM
[+0.35s] DEBUG: Prompt greeter with 1 message(s)</code></pre>
<p>My greeter appeared in a small window.
I don’t know what the fundamental problem was; I know basically nothing about this area of Linux.
I’ll probably learn more about it one day.
For now I’m content with having fixed my issue.</p>
    ]]></content>
    
</entry>
<entry>
    <title>2023 Project Review</title>
    <link href="https://blog.ielliott.io/2023-project-review" />
    
    <id>https://blog.ielliott.io/2023-project-review</id>
    
    <published>2024-01-17T09:40:00Z</published>
    <updated>2024-01-17T09:40:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/2023-project-review"><![CDATA[<p>Reflections on 2023's hobby projects.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/2023-project-review"><![CDATA[
      
      <div id="toc" style="white-space: normal;">
<h3>Contents</h3>
<ul>
<li><a href="#ipso">Ipso</a></li>
<li><a href="#ipso-scripts">Ipso scripts</a></li>
<li><a href="#laurel">Laurel</a></li>
<li><a href="#blog-site-generator-improvements">Blog site generator improvements</a></li>
<li><a href="#music-neon-rain">Music: “Neon Rain”</a></li>
<li><a href="#music-resurrect">Music: “Resurrect”</a></li>
<li><a href="#nominal-sets">Nominal Sets</a></li>
<li><a href="#hover-pill">Hover Pill</a></li>
<li><a href="#2d-visibility-tests">2D visibility tests</a></li>
<li><a href="#3d-graphics-fundamentals">3D graphics fundamentals</a></li>
<li><a href="#low-level-ir-compiler">Low-level IR compiler</a></li>
<li><a href="#parametric-polymorphism-in-cartesian-closed-categories">Parametric polymorphism in cartesian closed categories</a></li>
<li><a href="#talk-rust-and-functional-programming">Talk: Rust and functional programming</a></li>
<li><a href="#music-intro-theme">Music: “Intro Theme”</a></li>
<li><a href="#incremental-file-processing-denotationally">Incremental file processing, denotationally</a></li>
<li><a href="#single-program-web-apps">“Single program” web apps</a></li>
</ul>
</div>
<h2 id="ipso"><a href="#ipso">Ipso</a></h2>
<p><em>Ongoing</em></p>
<p><a href="https://ipso.dev" class="uri">https://ipso.dev</a></p>
<p><a href="https://github.com/LightAndLight/ipso" class="uri">https://github.com/LightAndLight/ipso</a></p>
<p>Ipso is a functional scripting language that I created so that I can write glue code and small scripts in a way that I enjoy.
In February I started using Ipso for some “real” scripts, so I wrote a <a href="https://github.com/LightAndLight/ipso/tree/main/vscode-ipso">VSCode extension</a>
and added a bunch of features and fixes based on what I experienced.
In May I added <a href="https://github.com/LightAndLight/ipso/blob/main/CHANGELOG.md#06">many new builtins</a>.
Writing the VSCode extension was exciting; simple things like syntax highlighting and keyword autocompletion give the programming language a new level of “tangibility”.</p>
<h2 id="ipso-scripts"><a href="#ipso-scripts">Ipso scripts</a></h2>
<p><em>February - March</em></p>
<p><a href="https://github.com/LightAndLight/git-explorer"><code>git-explorer</code></a> is a prototype for a Git URI scheme I came up with.
Sometimes I take notes alongside my code and commit them to Git repository,
I want to create hyperlinks to lines of code in a file at specific commit,
in the same way that I can permalink to code on GitHub or Gitlab.
It would be cool to serve a code-aware wiki from a project’s Git repo, similar to the way
<a href="https://www2.fossil-scm.org/home/doc/trunk/www/index.wiki">Fossil</a>
can serve code, docs, and more from a repository.
The first step in all of this is a format for hyperlinks to Git objects.
I’ll demonstrate by example, using <code>git-explorer</code> inside its own repository:</p>
<pre><code>$ ls -a
.  ..  flake.lock  flake.nix  .git  gitex  .gitignore

$ git log HEAD~1..HEAD
commit 7f0489dab4397232cf3425fbed87b7c3636394b0 (HEAD -&gt; main, origin/main)
Author: Isaac Elliott &lt;isaace71295@gmail.com&gt;
Date:   Wed May 31 11:52:11 2023 +1000

    use newer version of Ipso
    
$ gitex type git:object:7f0489dab4397232cf3425fbed87b7c3636394b0
commit

$ gitex show git:commit:7f0489dab4397232cf3425fbed87b7c3636394b0
tree 83f65fc9e11e9c8174a0822364ba411e1dbf6937
parent f880dc26e94129ebd7d688eacd9203cac0cb9964
author Isaac Elliott &lt;isaace71295@gmail.com&gt; 1685497931 +1000
committer Isaac Elliott &lt;isaace71295@gmail.com&gt; 1685497931 +1000

use newer version of Ipso

$ gitex type git:commit:7f0489dab4397232cf3425fbed87b7c3636394b0/tree
tree

$ gitex show git:commit:7f0489dab4397232cf3425fbed87b7c3636394b0/tree
100644 blob ea8c4bf7f35f6f77f75d92ad8ce8349f6e81ddba	.gitignore
100644 blob 6319f0e690d6037d6e70165c3aedbbf1a049b8b9	flake.lock
100644 blob f179ab98301cd132148e87f136566f2496e256ca	flake.nix
100755 blob ab5bac9c63cc9c8e5ca6da67ae7d8e5e58f9e68f	gitex

$ gitex show git:commit:7f0489dab4397232cf3425fbed87b7c3636394b0/tree/flake.nix | head -n 5
{
  inputs = {
    flake-utils.url = &quot;github:numtide/flake-utils&quot;;
    nix-filter.url = &quot;github:numtide/nix-filter&quot;;
    ipso.url = &quot;github:LightAndLight/ipso?commit=e7bf506bd8f85f00c7b00b795b587f79b5bb5d9d&quot;;
        
$ gitex uri flake.nix
git:blob:f179ab98301cd132148e87f136566f2496e256ca
git:commit:7f0489dab4397232cf3425fbed87b7c3636394b0/tree/flake.nix</code></pre>
<p><a href="https://github.com/LightAndLight/timespent"><code>timespent</code></a> helps me record what I’ve done during a work day.
When I start my work day, I <code>cd</code> to the directory that contains my time logs.
I call <code>timespent</code>, and my <code>EDITOR</code> (<a href="https://helix-editor.com/">Helix</a>, these days) opens today’s time log file.
If the file hasn’t been created yet, it’s initialised from a template.
Today’s time log file is located at <code>./YYYY-mm-dd-week/YYYY-mm-dd.txt</code>, where the directory has the date of this week’s Monday.
I record what I’ve done, save and exit, and the file is automatically committed.
If I run <code>timespent</code> again, change what I’ve recorded, then save and exit, the changes are rebased onto the commit for today’s log.</p>
<p>Each of these scripts is on the order of 100s of lines of Ipso code.
Writing them was super helpful for finding Ipso’s pain points.
They also validated the purpose of Ipso; I enjoyed writing these scripts more than I would have if I used Bash, Python, or Haskell.</p>
<h2 id="laurel"><a href="#laurel">Laurel</a></h2>
<p><em>March - May</em></p>
<p><a href="https://github.com/LightAndLight/laurel" class="uri">https://github.com/LightAndLight/laurel</a></p>
<p>Laurel is a query language experiment.
I’m perennially dissatisfied with SQL and continue to search for something better.
Laurel is an exploration inspired by <a href="https://dl.acm.org/doi/10.1145/202660.202667">The third manifesto</a>,
<a href="https://dl.acm.org/doi/10.1145/3236781">Relational algebra by way of adjunctions</a>,
and my experience with typed functional programming.</p>
<p>One part of the experiment is to have a single query language with multiple backends.
I implemented a REPL that can “connect” to two different backends: Postgres, and CSV files.
Here’s a demo of the CSV backend:</p>
<pre><code style="white-space: unset;">$ laurel repl
Welcome to the Laurel REPL. Type :quit to exit.
> :connect "csv" ["laurel-core/test/data/example.csv"]
connected

> :tables
table example {
  merchant : String,
  transaction type : String,
  amount : String,
  category : String
}

> :type tables
{ example : Relation { merchant : String, transaction type : String, amount : String, category : String } }

> tables.example
╭───────────────────┬───────────────────────────┬─────────────────┬───────────────────╮
│ merchant : String │ transaction type : String │ amount : String │ category : String │
├───────────────────┼───────────────────────────┼─────────────────┼───────────────────┤
│ Google            │ debit                     │ 10.00           │ tech              │
│ NAB               │ credit                    │ 5.00            │ finance           │
│ Spotify           │ debit                     │ 12.00           │ entertainment     │
│ Some Cafe         │ debit                     │ 22.00           │ eating out        │
│ Hotpot Restaurant │ debit                     │ 50.00           │ eating out        │
│ Woolworths        │ debit                     │ 38.00           │ groceries         │
│ NAB               │ credit                    │ 5.00            │ finance           │
╰───────────────────┴───────────────────────────┴─────────────────┴───────────────────╯

> :type (for row in tables.example yield row.merchant)
Relation String

> for row in tables.example yield row.merchant
╭───────────────────╮
│ _ : String        │
├───────────────────┤
│ Google            │
│ NAB               │
│ Spotify           │
│ Some Cafe         │
│ Hotpot Restaurant │
│ Woolworths        │
│ NAB               │
╰───────────────────╯

> :type (tables.example group by (\row -> row.`transaction type`))
Map String (Relation { merchant : String, transaction type : String, amount : String, category : String })

> tables.example group by (\row -> row.`transaction type`)
╭──────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ key : String │ value : Relation { merchant : String, transaction type : String, amount : String, category : String } │
├──────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ credit       │ ╭───────────────────┬───────────────────────────┬─────────────────┬───────────────────╮               │
│              │ │ merchant : String │ transaction type : String │ amount : String │ category : String │               │
│              │ ├───────────────────┼───────────────────────────┼─────────────────┼───────────────────┤               │
│              │ │ NAB               │ credit                    │ 5.00            │ finance           │               │
│              │ │ NAB               │ credit                    │ 5.00            │ finance           │               │
│              │ ╰───────────────────┴───────────────────────────┴─────────────────┴───────────────────╯               │
│ debit        │ ╭───────────────────┬───────────────────────────┬─────────────────┬───────────────────╮               │
│              │ │ merchant : String │ transaction type : String │ amount : String │ category : String │               │
│              │ ├───────────────────┼───────────────────────────┼─────────────────┼───────────────────┤               │
│              │ │ Woolworths        │ debit                     │ 38.00           │ groceries         │               │
│              │ │ Hotpot Restaurant │ debit                     │ 50.00           │ eating out        │               │
│              │ │ Some Cafe         │ debit                     │ 22.00           │ eating out        │               │
│              │ │ Spotify           │ debit                     │ 12.00           │ entertainment     │               │
│              │ │ Google            │ debit                     │ 10.00           │ tech              │               │
│              │ ╰───────────────────┴───────────────────────────┴─────────────────┴───────────────────╯               │
╰──────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────╯
</code></pre>
<p>I can also connect to to a Postgres database and import (a subset of) its schema:</p>
<pre><code>&gt; :connect &quot;postgres&quot; { host = &quot;localhost&quot;, database = &quot;test&quot; }
connected

&gt; :tables
table person {
  id : Int [PrimaryKey],
  name : String
}

table blah {
  x : Optional Int [Default(Some(0))]
}

&gt; tables.person
╭──────────┬───────────────╮
│ id : Int │ name : String │
├──────────┼───────────────┤
│ 262145   │ alice         │
│ 262146   │ bob           │
│ 262147   │ charlie       │
╰──────────┴───────────────╯</code></pre>
<p>This means there’s potential for multi-datasource queries.</p>
<p>I really enjoyed implementing the tabular pretty printer. The tables look really cool!
And building the bridge between Laurel types and Postgres schemas felt like magic when I got it working.</p>
<p>I don’t know what will happen to the typed functional version of Laurel.
I recently discovered <a href="https://en.wikipedia.org/wiki/Datalog">Datalog</a>, which seems a bit more elegant than the functional approach.
Next year I’ll probably investigate Datalog some more.</p>
<h2 id="blog-site-generator-improvements"><a href="#blog-site-generator-improvements">Blog site generator improvements</a></h2>
<p><em>May</em></p>
<p><a href="https://blog.ielliott.io/jekyll-to-hakyll" class="uri">https://blog.ielliott.io/jekyll-to-hakyll</a></p>
<p><a href="https://github.com/LightAndLight/lightandlight.github.io/blob/main/site.hs" class="uri">https://github.com/LightAndLight/lightandlight.github.io/blob/main/site.hs</a></p>
<p>I migrated this blog from Jekyll to Hakyll, and added a few upgrades.
Table of contents generation, heading anchors, and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mtext mathvariant="normal">MathML support </mtext><mspace width="0.333em"></mspace></mrow><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>a</mi><mo>→</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\text{MathML support } (\forall a. \; a \rightarrow a)</annotation></semantics></math> are the most significant features I added.</p>
<p>Moving my static site generator into Haskell gave me a greater feeling of agency over my site.
I started using Jekyll because it was the easiest path to get something set up on GitHub pages.
My default perspective was that I had to rely on the package authors to satisfy my needs.
Now that it’s in Haskell it’s something I feel like I own, and it’s easier to realise that if there isn’t a package that does what I
want then I can make it exist.</p>
<h2 id="music-neon-rain"><a href="#music-neon-rain">Music: “Neon Rain”</a></h2>
<p><em>May - June</em></p>
<iframe style="margin-bottom: 1rem" title="Neon Rain by Isaac Elliott" width="100%" height="300" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/1532726281&amp;color=%23379392&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&amp;visual=true">
</iframe>
<p>I’ve been getting into ambient / soundtrack music over the past few years.
I kept playing around with synths, but couldn’t figure out how to write a piece from start to finish.
My background is in rock and metal, which have a <em>lot</em> of constraints that I’m familiar with (forms, instrumentation, etc.).
“Neon Rain” was born from my commitment to <em>just make something</em>.
I decided on a theme—melancholy, cyberpunk—and found some pictures on <a href="https://www.artstation.com">ArtStation</a>
that I found compelling.
Then I sat down and made music.
I tried to design sounds by following my sense of taste, guided by the images I’d chosen.
This required me to bypass my inner critic, who has a (n admittedly pretty whacky) desire to “be original”.
I welcomed any idea that would make the music more effective instead of dismissing most ideas because they seemed cliché.
The end result is my first full ambient / soundtrack -style piece.
I made <em>something</em>, and that feels like a breakthrough.</p>
<h2 id="music-resurrect"><a href="#music-resurrect">Music: “Resurrect”</a></h2>
<p><em>May - June</em></p>
<iframe style="margin-bottom: 1rem" title="Resurrect by Isaac Elliott" width="100%" height="300" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/1536670189&amp;color=%23379392&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&amp;visual=true">
</iframe>
<p>I’ve saved almost every <a href="https://www.reaper.fm">Reaper</a> project that I’ve created since I started producing music in 2018.
I went back through my archives and found a project that was basically a complete song.
I thought it was cool, so I decided to mix it for release.
Even though I haven’t done very much music production in the past 1-2 years, I was able to create what is overall my best mix so far.
I think the main reason for this was that I successfully used a professional song (<a href="https://www.youtube.com/watch?v=bNlUJgP3Lwk">Slow Violence by Caligula’s Horse</a>) as a reference mix.
<a href="https://www.youtube.com/@DanWorrall">Dan Worrall</a> talked about <a href="https://www.youtube.com/watch?v=kGW8SDFikeg">reference mixes as a “palate cleanser for the ears”</a>,
and this really stuck with me.</p>
<h2 id="nominal-sets"><a href="#nominal-sets">Nominal Sets</a></h2>
<p><em>May - July</em></p>
<p><a href="https://github.com/LightAndLight/binders.rs" class="uri">https://github.com/LightAndLight/binders.rs</a></p>
<p><a href="https://blog.ielliott.io/nominal-sets" class="uri">https://blog.ielliott.io/nominal-sets</a></p>
<p><a href="https://blog.ielliott.io/nominal-sets-proofs" class="uri">https://blog.ielliott.io/nominal-sets-proofs</a></p>
<p>Nominal Sets is a theory of <a href="https://en.wikipedia.org/wiki/Name_binding">name binding</a>.
I started writing a Rust library based on the idea, and realised that I needed to understand the theory better if I wanted judge how well my library served its purpose.
To this end, I wrote an introduction to Nominal Sets.
As a mathematical exercise I proved many theorems by hand, which I included in a separate appendix.
I feel like I leveled up my mathematical literacy.</p>
<p>One important tool I discovered was <a href="https://www.slq.qld.gov.au/">my state library’s online catalogue</a>.
I felt like I had reach the limit of what I could glean from the ~3 introductory Nominal Sets papers,
and I needed to read <a href="https://www.cambridge.org/core/books/nominal-sets/80F2B0C1B78A1DC309072CCEDAA88422">the book on Nominal Sets</a>
to make progress.
I didn’t want to buy it, though, because it seemed too niche for my small bookshelf.
Fortunately, the Queensland state library has a full digital copy that I can read for free.
As expected, the book had what I needed to get past my mental blocks.</p>
<p>This is my biggest mathematical project and my biggest writing project to date.
The proofs took ~4 weeks to finish.
In the end, I concluded that the Rust library is basically okay from a mathematical point of view.
It still needs some UX and performance improvements, though.</p>
<h2 id="hover-pill"><a href="#hover-pill">Hover Pill</a></h2>
<p><em>June</em></p>
<p><a href="https://github.com/LightAndLight/hover-pill" class="uri">https://github.com/LightAndLight/hover-pill</a></p>
<div style="margin-bottom: 1rem; display: flex; flex-direction: row; align-items: center; justify-content: space-between;">
<img alt="Hover Pill resting on a platform in the open sky." width="30%" src="https://github.com/LightAndLight/hover-pill/raw/main/screenshots/level.png"><img alt="The Hover Pill level editor." width="30%" src="https://github.com/LightAndLight/hover-pill/raw/main/screenshots/level-editor.png"><img alt="Hover Pill flying through an opening in a wall." width="30%" src="https://github.com/LightAndLight/hover-pill/raw/main/screenshots/other-level.png">
</div>
<p>Hover Pill is a puzzle game I created in 2022 to learn the <a href="https://bevyengine.org/">Bevy game engine</a>.
You fly a capsule-shaped object through obstacles to reach a goal.
This year I added a level editor, which completes the project.</p>
<p>You can play the web version <a href="https://blog.ielliott.io/hover-pill">here</a>.</p>
<h2 id="2d-visibility-tests"><a href="#2d-visibility-tests">2D visibility tests</a></h2>
<p><em>July</em></p>
<p><a href="https://github.com/LightAndLight/2d-visibility" class="uri">https://github.com/LightAndLight/2d-visibility</a></p>
<p>I started thinking about how to make games with good agent simulations.
Visibility seems like an important primitive; there are a lot of actions that an agent should only take if they can “see” an object.
These are some experiments in calculating which objects are visible from a particular point.</p>
<div style="display: flex; flex-direction: row; justify-content: space-between;">
<div style="width: 48%; display: flex; flex-direction: column; align-items: center;">
<video width="100%" src="https://github.com/LightAndLight/2d-visibility/raw/main/videos/exercise_2.webm" controls="controls">
</video>
<p>Exercise 1: simple line of sight</p>
</div>
<div style="width: 48%; display: flex; flex-direction: column; align-items: center;">
<video width="100%" src="https://github.com/LightAndLight/2d-visibility/raw/main/videos/exercise_2.webm" controls="controls">
</video>
<p>Exercise 2: hiding occluded objects</p>
</div>
</div>
<div style="display: flex; flex-direction: row; justify-content: space-between;">
<div style="width: 48%; display: flex; flex-direction: column; align-items: center;">
<video width="100%" src="https://github.com/LightAndLight/2d-visibility/raw/main/videos/exercise_3.webm" controls="controls">
</video>
<p>Exercise 3: visual feedback for occluded areas</p>
</div>
<div style="width: 48%; display: flex; flex-direction: column; align-items: center;">
<video width="100%" src="https://github.com/LightAndLight/2d-visibility/raw/main/videos/exercise_4.webm" controls="controls">
</video>
<p>Exercise 4: hiding occluded objects</p>
</div>
</div>
<h2 id="3d-graphics-fundamentals"><a href="#3d-graphics-fundamentals">3D graphics fundamentals</a></h2>
<p><em>July - August</em></p>
<p><a href="https://github.com/LightAndLight/3d-graphics-fundamentals" class="uri">https://github.com/LightAndLight/3d-graphics-fundamentals</a></p>
<p><img alt="A 3D scene rendered using physically based techniques at 60FPS." width="100%" src="https://github.com/LightAndLight/3d-graphics-fundamentals/raw/main/screenshot.png"></p>
<p>Computer graphics has always been intimidating and difficult for me, but I keep making progress.
Last year I <a href="http://blog.ielliott.io/2022-project-review#ray-tracing-in-one-weekend">implemented an offline ray tracing renderer</a>
and a <a href="http://blog.ielliott.io/2022-project-review#wgpu-mandelbrot">GPU-based mandelbrot fractal renderer</a>.
This year, my big graphics project was realtime physically-based 3D rendering.</p>
<p>There aren’t any tutorials or courses for something like this.
Instead, there are examples of specific techniques spread across books, papers, blog posts, and talks, and it was up to me to piece them together.
Using only a <a href="https://docs.rs/wgpu/latest/wgpu/">GPU library</a> and <a href="https://docs.rs/cgmath/latest/cgmath/">linear algebra library</a>, I implemented:</p>
<ul>
<li>Physically-based shading</li>
<li>High dynamic range rendering with automatic exposure and tone mapping</li>
<li>Directional and point lights</li>
<li>Shadow mapping (fitted to view frustum for directional lights, omnidirectional for point lights)</li>
<li>HDRI skybox</li>
</ul>
<p>I also integrated <a href="https://github.com/emilk/egui">the egui immediate mode GUI</a> so that I could add realtime debugging controls.</p>
<p>Like many good things, this project was <em>really</em> hard.
There were many times when I felt like there was no way to make progress because I didn’t know enough.
Whenever this happened, I eventually <em>did</em> make progress by breaking the problem into smaller pieces and trying to understand each piece from first principles.</p>
<p>One place I got stuck in dealing with automatic exposure.
Physically-based rendering means using physically plausible values for quantities like “the amount of light visible at a pixel”,
but screens generally take an 8-bit value for each pixel colour.
You have to figure out how to map your physical pixel illuminations to the range of 0 to 255.
A simple mapping like “divide every value by the max value in the scene” looks wrong, because of the <a href="https://en.wikipedia.org/wiki/Dynamic_range#Photography">dynamic range</a> of the scene.
The darkest area and the lightest area can differ by many orders of magnitude.
<a href="https://en.wikipedia.org/wiki/Tone_mapping">Tone mapping</a> came up a lot in discussions of HDR rendering, so I thought it was the answer.
But it’s not; <a href="https://en.wikipedia.org/wiki/Exposure_(photography)">exposure</a> is what I was looking for.
In particular, I wanted automatic exposure so that scenes with different brightnesses all looked good.
I couldn’t find anything that really spelled out the implementation of autoexposure in a HDR renderer,
so I had to develop a physically-based intuition of what my camera was supposed to do.
Only then did the math make enough sense for me to be able to implement something.</p>
<p>Part of the reason I did this project was to see if I have what it takes to do computer graphics professionally.
I think this shows that I at least have potential.</p>
<h2 id="low-level-ir-compiler"><a href="#low-level-ir-compiler">Low-level IR compiler</a></h2>
<p><em>August - September</em></p>
<p><a href="https://github.com/LightAndLight/metis" class="uri">https://github.com/LightAndLight/metis</a></p>
<p><code>metis</code> was supposed to be an implementation of some type systems / compilation research I’m doing,
but it ended up being a playground for implementing a low-level intermediate representation that compiles to assembly.
I implemented register allocation and branching and basic blocks with arguments, and by the time I got to calling conventions I realised how far off track I’d gone.
It was fun while it lasted, but right now I value testing the research idea more than I value learning how to reimplement LLVM.</p>
<p>The research idea builds on <a href="https://blog.ielliott.io/sized-hkts">Statically Sized Higher-kinded Polymorphism (2020)</a>.
In that project, I demonstrated higher-kinded polymorphism in a language with Rust-like monomorphisation.
Monomorphising polymorphic functions generates a multiplicative amount of code:
a function with one type argument has a monomorphisation for every type,
and a function with two type arguments has a monomorphisation for (every type) squared.
Higher-kinded polymorphism compounds the issue.</p>
<p>This treatment of polymorphism lies at one end of a continuum.
At the other end we have single compilation, where code for a function is generated once regardless of how many type parameters it takes.
A singly-compiled polymorphic function needs to work with <em>any</em> input type.
Languages like Haskell achieve this by ensuring that polymorphic arguments are boxed.
Every polymorphic function is compiled once, taking and returning pointers for values with polymorphic type.
In these languages, any value may be passed to a polymorphic function, so every value must be boxed.
This significantly increases the amount of computation spent on managing heap allocations,
and decreases cache coherency.
A polymorphic function on
<a href="https://hackage.haskell.org/package/vector-0.13.1.0/docs/Data-Vector.html#t:Vector">Vector</a>s like <a href="https://hackage.haskell.org/package/vector-0.13.1.0/docs/Data-Vector.html#v:foldl-39-">foldl’</a>
operates on an array of pointers to values, rather than an array of values.
And an <a href="https://hackage.haskell.org/package/base-4.19.0.0/docs/Data-IORef.html#t:IORef">IORef</a> (the standard mutable reference)
is a pointer to a pointer to a pointer to a value<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>, instead of just a pointer to a value.</p>
<p>I want to explore a technique that makes polymorphic-values-are-pointers less infectious,
i.e. that doesn’t require every value to be boxed just in case it’s passed to a polymorphic function.
In short, the technique is this:
for each type variable of kind <code>Type</code>, pass a <a href="https://en.wikipedia.org/wiki/Virtual_method_table">vtable</a> containing a copy constructor,
move constructor, size information, etc.
For each type variable of kind <code>Type -&gt; Type</code>, pass a “vtable constructor”, which is a function from vtable to vtable.
A singly-compiled polymorphic function uses a type variable’s vtable to operate on values of the corresponding polymorphic type.
We can selectively monomorphise using <a href="https://mpickering.github.io/posts/2017-03-20-inlining-and-specialisation.html#what-is-specialisation">specialisation</a>.</p>
<p>It’s a surprisingly uncommon approach.
Swift is the only language I’ve heard of <a href="https://www.youtube.com/watch?v=ctS8FzqcRug&amp;t=197s">that does this</a> (for type variables of kind <code>Type</code>),
and I don’t know any languages that do it for higher-kinded types.
It’s completely feasible, and there are a lot of details that are best worked out by writing the compiler.
Also it will require benchmarking to check whether it’s practical.</p>
<p>I’ve got <a href="https://github.com/LightAndLight/metis/tree/use-llvm">a branch</a> where I’ve replaced all my IR stuff with LLVM so that I can focus on the research ideas.</p>
<h2 id="parametric-polymorphism-in-cartesian-closed-categories"><a href="#parametric-polymorphism-in-cartesian-closed-categories">Parametric polymorphism in cartesian closed categories</a></h2>
<p><em>September</em></p>
<p><a href="https://github.com/LightAndLight/ccc-polymorphism" class="uri">https://github.com/LightAndLight/ccc-polymorphism</a></p>
<p>I’m still fascinated by the <a href="https://ncatlab.org/nlab/show/relation+between+type+theory+and+category+theory">Curry-Howard-Lambek correspondence</a>:
that the simply-typed lambda calculus (STLC) can be seen as a syntax for <a href="https://ncatlab.org/nlab/show/cartesian+closed+category">cartesian closed categories</a>,
and dually that cartesian closed categories are a categorical semantics for STLC.
<a href="http://conal.net">Conal Elliott</a>’s <a href="http://conal.net/papers/compiling-to-categories/">Compiling to Categories (2017)</a> and <a href="http://conal.net/papers/calculating-compilers-categorically/">Calculating Compilers Categorically (2018) (draft)</a>
continue to stoke my imagination.</p>
<p>I found myself wondering how to extend all of this to cover parametric polymorphism.
What is the simpliest categorical semantics for <a href="https://en.wikipedia.org/wiki/System_F">System F</a>,
and how do I exploit it to build better compilers?</p>
<p>The existing literature is currently too advanced for me, so I toggled between reading it and then “just trying to figure things out myself” in Agda or on paper.
One cool thing that came up pretty early is the role of <a href="https://ncatlab.org/nlab/show/adjoint+functor">adjoint functors</a> in
<a href="https://ncatlab.org/nlab/show/quantification#LawvereQuantifier">modeling universal and existential quantification</a>.</p>
<p>So far all my progress has been conceptual. It’s a slow burn.</p>
<h2 id="talk-rust-and-functional-programming"><a href="#talk-rust-and-functional-programming">Talk: Rust and functional programming</a></h2>
<p><em>September</em></p>
<p><a href="https://github.com/LightAndLight/rust-and-fp" class="uri">https://github.com/LightAndLight/rust-and-fp</a></p>
<p><a href="https://blog.ielliott.io/talks/rust-and-fp.pdf" class="uri">https://blog.ielliott.io/talks/rust-and-fp.pdf</a></p>
<p>A presentation I did for the <a href="https://bfpg.org">Brisbane Functional Programming Group</a>’s September meetup.
As an avid Haskeller, I’ve contributed to discussions where attempts to define “functional programming”
were used as gatekeeping and as a fundamental driver of <a href="https://blog.aurynn.com/2015/12/16-contempt-culture">contempt culture</a>.
In this talk I attempt to move our discussion of “functional programming” away from all of that,
while also introducing Rust.</p>
<p>The slides have speaker notes attached, if you’re interested in roughly what I said during the talk.</p>
<h2 id="music-intro-theme"><a href="#music-intro-theme">Music: “Intro Theme”</a></h2>
<p><em>October - November</em></p>
<iframe style="margin-bottom: 1rem" title="Intro Theme by Isaac Elliott" width="100%" height="300" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/1662315852&amp;color=%23379392&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&amp;visual=true">
</iframe>
<p>“Intro Theme” (because I couldn’t think of a better name) is a cinematic style piece.
I had less artistic / creative constraints than in <a href="#music-neon-rain">“Neon Rain”</a>, but still aimed to bypass my inner critic.
This time around I was mainly focused on composing something that didn’t feel repetitive.
Good composers have a way of making music sound “alive”: ever-changing, yet cohesive.
One tactic I used to approach this ideal was to avoid sonic repetition.
My theory is that hearing a bar or two repeated identically within a short time frame
(which is super easy to do in digital audio production by copying and pasting sections)
is antithetical to this quality of “life” I’m aiming for.
Instead of playing an arpeggio on a static synth patch, I added a lot of automation to the patch so that each repetition sounds subtly different.
I also tried to add “flourishes”, which is what I call short thematic sounds that add novelty and character to a piece.</p>
<h2 id="incremental-file-processing-denotationally"><a href="#incremental-file-processing-denotationally">Incremental file processing, denotationally</a></h2>
<p><em>November - December</em></p>
<p><a href="https://github.com/LightAndLight/incremental-file-processing" class="uri">https://github.com/LightAndLight/incremental-file-processing</a></p>
<p>Suppose I’ve got some data that I want to tidy up and use to plot a chart.
I have a CSV file of the raw data, so I write a program that parses the CSV,
extracts the columns I’m interested in, then decodes the contents of each row.
I’m left with a value of type <code>List (Double, Double)</code>, which I’ll feed to the plotting function.
I run the program and look at the chart.
I realise the Y-axis has the wrong label, so I change the arguments to the plotting function and re-run the program.
This repeats all of the data preparation, even though the raw CSV and the data processing functions haven’t changed.
It would be nice if my program could save the prepared data right before I plot it,
and reuse the saved data if it hasn’t changed between program runs.</p>
<p>This is an <a href="https://en.wikipedia.org/wiki/Incremental_computing">incremental computation</a> problem.
Typically the solutions talk about graphs, caches, change bits, hashing, and so on.
Lately I’ve been thinking really hard about denotational design, so I wanted to know how I should <em>think</em> about my incremental file processing problem.
In other words, what is its denotation?</p>
<p>The answer I’ve settled on is strings (or bytes more generally), file references, and functions between strings.
The core interface currently looks like this:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">File</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ot">from ::</span> <span class="dt">Filepath</span> <span class="ot">-&gt;</span> <span class="dt">File</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="ot">string ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">File</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="ot">mapFile ::</span> <span class="dt">Expr</span> (<span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span>) <span class="ot">-&gt;</span> <span class="dt">File</span> <span class="ot">-&gt;</span> <span class="dt">File</span></span></code></pre></div>
<p>And here’s what it <em>means</em>:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">⟦</mo><mrow><mtext mathvariant="monospace">𝙴𝚡𝚙𝚛 </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><msub><mo stretchy="false" form="postfix">⟧</mo><mtext mathvariant="normal">value</mtext></msub><mo>=</mo><mi>a</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">⟦</mo><mtext mathvariant="monospace">𝙵𝚒𝚕𝚎</mtext><msub><mo stretchy="false" form="postfix">⟧</mo><mtext mathvariant="normal">contents</mtext></msub><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="monospace">𝙵𝚒𝚕𝚎𝚙𝚊𝚝𝚑</mtext><mo>→</mo><mtext mathvariant="monospace">𝚂𝚝𝚛𝚒𝚗𝚐</mtext><mo stretchy="false" form="postfix">)</mo><mo>→</mo><mtext mathvariant="monospace">𝚂𝚝𝚛𝚒𝚗𝚐</mtext></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">⟦</mo><mtext mathvariant="monospace">𝚏𝚛𝚘𝚖</mtext><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">path</mtext><mo stretchy="false" form="postfix">)</mo><msub><mo stretchy="false" form="postfix">⟧</mo><mtext mathvariant="normal">contents</mtext></msub><mo>=</mo><mi>λ</mi><mtext mathvariant="normal">env</mtext><mi>.</mi><mspace width="0.278em"></mspace><mtext mathvariant="normal">env</mtext><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">path</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">⟦</mo><mtext mathvariant="monospace">𝚜𝚝𝚛𝚒𝚗𝚐</mtext><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">s</mtext><mo stretchy="false" form="postfix">)</mo><msub><mo stretchy="false" form="postfix">⟧</mo><mtext mathvariant="normal">contents</mtext></msub><mo>=</mo><mi>λ</mi><mtext mathvariant="normal">env</mtext><mi>.</mi><mspace width="0.278em"></mspace><mtext mathvariant="normal">s</mtext></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">⟦</mo><mtext mathvariant="monospace">𝚖𝚊𝚙𝙵𝚒𝚕𝚎</mtext><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">f</mtext><mo>,</mo><mtext mathvariant="normal">file</mtext><mo stretchy="false" form="postfix">)</mo><msub><mo stretchy="false" form="postfix">⟧</mo><mtext mathvariant="normal">contents</mtext></msub><mo>=</mo><mi>λ</mi><mtext mathvariant="normal">env</mtext><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟦</mo><mtext mathvariant="normal">f</mtext><msub><mo stretchy="false" form="postfix">⟧</mo><mtext mathvariant="normal">value</mtext></msub><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟦</mo><mtext mathvariant="normal">file</mtext><msub><mo stretchy="false" form="postfix">⟧</mo><mtext mathvariant="normal">contents</mtext></msub><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\llbracket \texttt{Expr } a \rrbracket_{\text{value}} = a
\\
\llbracket \texttt{File} \rrbracket_{\text{contents}} = (\texttt{Filepath} \rightarrow \texttt{String}) \rightarrow \texttt{String}
\\
\;
\\
\llbracket \texttt{from}(\text{path}) \rrbracket_{\text{contents}} = \lambda \text{env}. \; \text{env}(\text{path})
\\
\llbracket \texttt{string}(\text{s}) \rrbracket_{\text{contents}} = \lambda \text{env}. \; \text{s}
\\
\llbracket \texttt{mapFile}(\text{f}, \text{file}) \rrbracket_{\text{contents}} = \lambda \text{env}. \; \llbracket \text{f} \rrbracket_{\text{value}} (\llbracket \text{file} \rrbracket_{\text{contents}})
\end{array}
</annotation></semantics></math></p>
<p>My claim for this library is you can use the above as a mental model regardless of the implementation.
With this meaning as the guide post, I created implementations that interact with the file system and do incremental (re)computation across program runs.
The most sophisticated implementation is surprisingly Nix-like.</p>
<p>I think my approach is on the right track because I’ve been able to implement many different versions of increasing performance without (apparently) compromising the meaning of the interface.
The next step is to formalise all of this in Agda and prove that I haven’t compromised the interface.</p>
<h2 id="single-program-web-apps"><a href="#single-program-web-apps">“Single program” web apps</a></h2>
<p><em>December</em></p>
<p><a href="https://github.com/LightAndLight/misc/tree/main/20231129-single-program-web-apps" class="uri">https://github.com/LightAndLight/misc/tree/main/20231129-single-program-web-apps</a></p>
<p>This project is an attempt at writing web applications as a single program, instead of two (a frontend and a backend).
The programmer doesn’t write HTTP requests or API endpoints.
Whether or not the web application is instantiated as “client-side JavaScript communicating with a HTTP server over a network” is immaterial.
The same program should also be able to run standalone using <a href="https://webkitgtk.org/">WebKitGTK</a> and its native DOM API with no JavaScript or networking.
I’ve since learned that this is called <a href="https://en.wikipedia.org/wiki/Multitier_programming">“multi-tier programming”</a>,
of which <a href="https://web.archive.org/web/20220523022545/https://haste-lang.org/">Haste</a> and <a href="https://ocsigen.org">Ocsigen</a> are two notable examples.</p>
<p>Here’s an example program that runs <code>putStrLn "The button was clicked!"</code> when a button is clicked.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ot">app ::</span> <span class="dt">App</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>app <span class="ot">=</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  page</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>    (<span class="st">&quot;example&quot;</span> <span class="op">&lt;&gt;</span> <span class="st">&quot;click&quot;</span>)</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    ( <span class="dt">Html</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>        [ <span class="dt">Node</span> <span class="st">&quot;head&quot;</span> [] [<span class="dt">Node</span> <span class="st">&quot;title&quot;</span> [] [<span class="dt">Text</span> <span class="st">&quot;Example - click&quot;</span>]]</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>        , <span class="dt">Node</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>            <span class="st">&quot;body&quot;</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>            []</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>            [ <span class="dt">Node</span> <span class="st">&quot;p&quot;</span> [] [<span class="dt">Text</span> <span class="st">&quot;When you click the button, an IO action is run on the server.&quot;</span>]</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>            , <span class="dt">Node</span> <span class="st">&quot;button&quot;</span> [] [<span class="dt">Text</span> <span class="st">&quot;Click me!&quot;</span>] <span class="ot">`OnEvent`</span> (<span class="dt">Click</span>, <span class="fu">putStrLn</span> <span class="st">&quot;The button was clicked!&quot;</span>)</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>            ]</span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>        ]</span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>    )</span></code></pre></div>
<p>When instantiated as a web application it becomes a HTTP server that:</p>
<ul>
<li>On receiving a certain request, runs <code>putStrLn "The button was clicked!"</code> and responds</li>
<li>Serves a page at <code>/example/click</code> that
<ul>
<li>Contains HTML and JavaScript that
<ul>
<li>Sends the proper request to the server when the button is clicked</li>
</ul></li>
</ul></li>
</ul>
<p>More complex examples can
<a href="https://github.com/LightAndLight/misc/blob/main/20231129-single-program-web-apps/app/Main.hs#L64">pass values from UI to IO actions</a>,
<a href="https://github.com/LightAndLight/misc/blob/main/20231129-single-program-web-apps/app/Main.hs#L85">embed IO results in the UI</a>,
and <a href="https://github.com/LightAndLight/misc/blob/main/20231129-single-program-web-apps/app/Main.hs#L196">fork threads that can trigger events that the UI responds to</a>.
Interactivity is defined using <a href="https://en.wikipedia.org/wiki/Functional_reactive_programming">functional-reactive programming</a>.</p>
<p>I wrote a <a href="https://github.com/LightAndLight/misc/tree/main/20231129-single-program-web-apps/compiler-plugin">GHC compiler plugin</a> for the first time as part of this project.
For the code to really feel like a single program, I needed a way to compile regular Haskell functions to JavaScript.
Inspired by <a href="https://github.com/compiling-to-categories/concat">concat</a>, I wrote a hacky GHC core plugin that reifies a Haskell expression of type <code>a</code> into a syntax tree of type <code>Expr a</code>.
When the program runs, it has access to both the native value and its corresponding syntax tree, so it can choose between evaluating natively or compiling to JavaScript.
It works for simple examples but won’t scale.
For proper code reuse this “quote” operator needs access to all the source code used to define the term being quoted, which isn’t readily available in a core plugin.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p><code>IORef</code> is a boxed (pointer number 1) <a href="https://hackage.haskell.org/package/base-4.16.3.0/docs/GHC-Exts.html#t:MutVar-35-">MutVar#</a>,
which is a pointer (pointer number 2) to a boxed (pointer number 3) value.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
    ]]></content>
    
</entry>
<entry>
    <title>Diablo 1 in 2023</title>
    <link href="https://blog.ielliott.io/diablo-1-in-2023" />
    
    <id>https://blog.ielliott.io/diablo-1-in-2023</id>
    
    <published>2023-07-14T00:00:00Z</published>
    <updated>2023-07-14T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/diablo-1-in-2023"><![CDATA[<p>My experience playing the original Diablo for the first time.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/diablo-1-in-2023"><![CDATA[
      
      <div id="toc">
<h3>Contents</h3>
<ul>
<li><a href="#music">Music</a></li>
<li><a href="#setting-and-story">Setting and Story</a></li>
<li><a href="#gameplay">Gameplay</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
</div>
<p>I didn’t know another <a href="https://en.wikipedia.org/wiki/Diablo_(series)">Diablo</a> game was coming until I saw advertisements for <a href="https://en.wikipedia.org/wiki/Diablo_IV">Diablo 4</a> on buses around the city.
Around the same time I was researching the origins of <a href="https://en.wikipedia.org/wiki/Guild_Wars">Guild Wars</a>, one of my favourite games from my early teens.
I learned that the early <a href="https://en.wikipedia.org/wiki/Blizzard_Entertainment">Blizzard</a> games—Warcraft, Warcraft 2, Diablo, and Starcraft—are sort of “direct technical ancestors” to Guild Wars:
<a href="https://en.wikipedia.org/wiki/ArenaNet">ArenaNet</a>, the studio that created Guild Wars, was created in 2000 by some important former Blizzard employees<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>.
Combined with my general sense of the Diablo series’ renown in video game history, I started getting curious about what the Diablo games would be like to play.</p>
<p>I’m kind of allergic to buying something as highly advertised as Diablo 4, and it currently costs AUD110 which is a bit expensive relative to my mild sense of curiosity.
I’m also skeptical of more modern “loot-based” or “progression-based” games, where there’s potential for a sort of “superficial feel-good feedback loop”: increasing your character’s stats so that you can fight stronger enemies so that you can increase your character’s stats, ad infinitum.
This ruled out Diablo 3 for the time being.
Faced with the choice between <a href="https://en.wikipedia.org/wiki/Diablo_II">Diablo 2</a> and <a href="https://en.wikipedia.org/wiki/Diablo_(video_game)">Diablo 1</a>, I chose the original (which from now on I’ll just call “Diablo”).
Might as well start at the beginning.
I recently finished the game<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>, and this post is about my experience.</p>
<h2 id="music"><a href="#music">Music</a></h2>
<p>Diablo turned 26 this year.
It’s the second oldest game I’ve played to completion, after <a href="https://en.wikipedia.org/wiki/Myst">Myst (1993)</a>.
Many elements of the game, such as graphics, gameplay, and narrative show their age and have been obsoleted by modern titles.
The part of the game that I think has aged the best, and impressed me the most, is the music.</p>
<p>The <a href="https://www.youtube.com/watch?v=AnMR6SOBa9k">Tristram theme</a> plays every time you return to the town after dungeon crawling,
and each time it was a pleasure to hear.
It still evokes feelings of spaciousness and release, while still keeping a sort of dark undertone.
Some of my favourite parts are:
the open acoustic guitar chords with ping-pong delay (<a href="https://youtu.be/AnMR6SOBa9k?t=0">00:00</a>, <a href="https://youtu.be/AnMR6SOBa9k?t=95">01:35</a>),
the use of guitar harmonics (<a href="https://youtu.be/AnMR6SOBa9k?t=29">00:29</a>, <a href="https://youtu.be/AnMR6SOBa9k?t=89">01:29</a>),
the brooding fingerstyle melody (<a href="https://youtu.be/AnMR6SOBa9k?t=44">00:44</a>),
the reverbed recorder-sounding flute instrument (<a href="https://youtu.be/AnMR6SOBa9k?t=100">01:40</a>),
and creative slide effects (<a href="https://youtu.be/AnMR6SOBa9k?t=130">02:10</a>).
The whole song is wonderful.
As a bonus: <a href="https://www.youtube.com/@8bitMusicTheory">8-bit music theory</a> recently did <a href="https://www.youtube.com/watch?v=2F_zsDWJyrM">an analysis of the song</a> which I really enjoyed.</p>
<p>As you venture deeper into the dungeon under the town, the music gets increasingly creepy.
I found it unsettling and unpleasant at times, especially when I entered a new area for the very first time with no idea what I’d find.
I appreciated the use of vocal samples, such as
<a href="https://youtu.be/gXUcwprvldc?t=822">pitch-shifted / reversed laughter</a>,
<a href="https://youtu.be/gXUcwprvldc?t=878">crying babies</a>,
<a href="https://youtu.be/gXUcwprvldc?t=1170">creepy moans and ragged breathing</a>,
to cement the hellish atmosphere.
Even though this is an isometric game (not the most immersive of player viewpoints), there were times when I actually felt jumpy and on edge.
I think the music was largely responsible for this.</p>
<p>Having finished the game once I probably won’t play Diablo again, but I will <em>definitely</em> revisit the soundtrack.</p>
<h2 id="setting-and-story"><a href="#setting-and-story">Setting and Story</a></h2>
<p><a href="https://web.archive.org/web/20081203054022/http://ftp.blizzard.com/pub/misc/Diablo.PDF">The game manual</a> does a lot of world-building.
I enjoyed reading it before jumping in.
The game itself has a very narrow setting (a village and a dungeon), and it was fun to imagine that the story I played was part of a larger “living” world.
Somehow the extra setting details made the game more enjoyable, even though they were “merely” imaginary.</p>
<p>Some of the manual’s world-building was revealed in game, through conversations with townsfolk, and books scattered throughout the dungeon.
Reading the manual beforehand reduced the impact and intrigue of those moments.
I would have really enjoyed a more methodical gameplay-based revelation of most of the things I read in the manual.
That said, it’s a lot cheaper and easier to convey that stuff through writing than it is through a game, so the way Blizzard did things seems reasonable given the game’s scope.</p>
<h2 id="gameplay"><a href="#gameplay">Gameplay</a></h2>
<p>I left-clicked a <em>lot</em>.
The combat mechanics were trivial: click to attack.
I started to worry that this game was more <a href="https://en.wikipedia.org/wiki/Cookie_Clicker">Cookie Clicker</a> than RPG,
but as I got deeper into the dungeon I found harder enemies that required better tactics to defeat.
Some melee enemies swarmed and interrupted my attack when they damaged me, so I had to fight them one-on-one in doorways and corridors (a classic roguelike tactic).
Others ran away to attack from afar, and I found I could herd them one-by-one into corners for a guaranteed kill.</p>
<p>Despite the simplicity of the controls, I found myself quite engaged with the game.
It felt like there were stakes; dying seemed consequential even though I could reload a saved game.
Getting swarmed by enemies made my heart rate rise, and narrowly escaping death was a real relief.</p>
<p>I was pleasantly surprised to find that the character attributes (strength, magic, dexterity, and vitality) were all useful.
When a warrior’s “primary attribute” is “strength” my first inclination is to maximise strength.
I did this in my first attempt as a warrior, and I got stuck about half way down because the enemies were too strong.
When I made a new warrior and distributed my attribute points more evenly, I made more progress more quickly.
I eventually beat the game on that character, but not without a struggle.
Even though I paid more attention to my non-primary attributes, I had still neglected my resistances (magic, fire, and lightning).
There was a point where I thought I’d have to give up on the final level, until I found a way to boost my fire resistance enough to make progress.</p>
<p>Diablo definitely seems designed for multiple playthroughs.
There are three classes, and I expect they all play differently.
There were some enemy types that appeared for my first character that didn’t for my second character.
The dungeon layouts are mostly randomised, too.
What would it be like to play as a Sorceror?
What else I didn’t see in the dungeons?
If video games were more scarce then my current level of curiosity would be enough for another playthrough, or maybe two.
But in 2023 I’m surrounded by thousands of incredible games, so I feel like the ~15 hours I’ve played is just the right amount of Diablo.</p>
<h2 id="conclusion"><a href="#conclusion">Conclusion</a></h2>
<p>I had a good time!
I guess the fact that it held up as well as it did should be evidence that it’s a good game.
I’m glad to have discovered another great game soundtrack and its composer (<a href="https://en.wikipedia.org/wiki/Matt_Uelmen">Matt Uelmen</a>).
Finally, I’m grateful to have experienced another piece of gaming history.
If services like <a href="https://www.gog.com">Good Old Games</a> didn’t exist then I probably would have just missed out.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Aside: <a href="https://youtu.be/1faaOrtHJ-A?t=143">Here’s a fun video</a> of <a href="https://www.codeofhonor.com/">Patrick Wyatt</a> (one of ArenaNet’s founders) talking about network programming in Warcraft, Diablo, and Guild Wars.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>I bought the <a href="https://www.gog.com/en/game/diablo">DRM-free version of Diablo + Hellfire on Good Old Games</a>.<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
    ]]></content>
    
</entry>
<entry>
    <title>Nominal Sets</title>
    <link href="https://blog.ielliott.io/nominal-sets" />
    
    <id>https://blog.ielliott.io/nominal-sets</id>
    
    <published>2023-07-04T06:41:00Z</published>
    <updated>2023-07-04T06:41:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/nominal-sets"><![CDATA[<p>Developing a <a href="https://github.com/LightAndLight/binders.rs">variable binding library</a> for Rust, based on the
theory of nominal sets.</p>
]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/nominal-sets"><![CDATA[
      
      <div class="intro-wrapper">
<div class="intro">
<p>For years I’ve used <a href="https://en.wikipedia.org/wiki/De_Bruijn_index">De
Bruijn indices</a>, in part because
of Haskell’s <a href="https://hackage.haskell.org/package/bound"><code>bound</code></a> library, which abstracts (pun
intended) De Bruijn indexed binders in a simple and type-safe way. Having learned to “think” using de Bruijn indices, I naturally used them when I wrote
<a href="https://github.com/lightandlight/ipso">Ipso</a>, which is written in Rust. I wished I had <code>bound</code>, so I tried to port it to
Rust. Unfortunately, <code>bound</code> relies on <a href="https://en.wikipedia.org/wiki/Polymorphic_recursion">polymorphic
recursion</a>, which Rust
<a href="https://github.com/rust-lang/rust/issues/4287#issuecomment-11846582">doesn’t really support</a>.</p>
<p>Writing all that variable binding machinery in Rust was tolerable, but Ipso probably isn’t the last
programming language that I’ll build with Rust. When it’s time for me to build the next one, I’d
like to use a variable binding library instead. I think
<a href="https://docs.rs/moniker/latest/moniker/"><code>moniker</code></a> is the only<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> such library on
<a href="https://crates.io/">crates.io</a>, and I might yet use it. In the meantime, I’d
like to explore an alternative way of tackling the problem, inspired by a formalism called “nominal sets”.</p>
</div>
<div id="toc">
<h3>Contents</h3>
<ul>
<li><a href="#why-did-i-write-this">Why did I write this?</a></li>
<li><a href="#names-and-binders">Names and binders</a></li>
<li><a href="#nominal-sets">Nominal sets</a>
<ul>
<li><a href="#names">Names</a></li>
<li><a href="#permutations">Permutations</a>
<ul>
<li><a href="#permutations-on-functions">Permutations on functions</a></li>
</ul></li>
<li><a href="#support">Support</a>
<ul>
<li><a href="#minimal-support">Minimal support</a></li>
<li><a href="#the-support-of-a-function">The support of a function</a></li>
</ul></li>
<li><a href="#freshness">Freshness</a></li>
<li><a href="#name-binding">Name binding</a></li>
<li><a href="#the-category-of-nominal-sets">The category of nominal sets</a></li>
<li><a href="#some-adjunctions">Some adjunctions</a></li>
</ul></li>
<li><a href="#showing-off">Showing off</a>
<ul>
<li><a href="#alpha-equivalence">Alpha equivalence</a></li>
<li><a href="#capture-avoiding-substitution">Capture-avoiding substitution</a></li>
</ul></li>
<li><a href="#final-thoughts">Final thoughts</a></li>
<li><a href="#appendix-a-proofs">Appendix A: Proofs</a></li>
</ul>
</div>
</div>
<h2 id="why-did-i-write-this"><a href="#why-did-i-write-this">Why did I write this?</a></h2>
<p>I have two reasons for writing this article. The first is to improve my understanding of
nominal sets, and my general mathematical ability.
Years ago I <a href="https://blog.ielliott.io/writing%3E">wrote about</a> my sense of the importance of writing,
and that line of reasoning continues to motivate me. More recently, <a href="http://www.paulgraham.com">Paul Graham</a> has written a much
more eloquent <a href="http://www.paulgraham.com/words.html">essay</a> on the topic.</p>
<p>The second is to contribute another introduction to nominal sets. I learned about nominal sets from
primary sources: a book (via my state library) and few papers from the pioneering authors, and slides from tutorials they’d given.
In total, five or six resources from a couple of authors. When I didn’t understand something I cycled
between resources, as if trying to triangulate an understanding. I think that more explanations, written by different people, would have increased the chances
of finding an explanation that clicked for me. While I cover the same introductory topics
as the primary sources, I hope that I’ll do it differently enough to be valuable to someone.</p>
<h2 id="names-and-binders"><a href="#names-and-binders">Names and binders</a></h2>
<p>Here is the core Rust implementation of my nominal-sets-inspired approach:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">mod</span> name <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="at">#[</span>derive<span class="at">(</span><span class="bu">Debug</span><span class="op">,</span> <span class="bu">PartialEq</span><span class="op">,</span> <span class="bu">Eq</span><span class="op">,</span> <span class="bu">Hash</span><span class="op">,</span> <span class="bu">Clone</span><span class="op">,</span> <span class="bu">Copy</span><span class="at">)]</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">pub</span> <span class="kw">struct</span> Name(<span class="dt">usize</span>)<span class="op">;</span> <span class="co">// (1)</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  <span class="pp">lazy_static!</span> <span class="op">{</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>      <span class="kw">static</span> <span class="kw">ref</span> COUNTER<span class="op">:</span> AtomicU64 <span class="op">=</span> <span class="pp">AtomicU64::</span>new(<span class="dv">0</span>)<span class="op">;</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn</span> fresh() <span class="op">-&gt;</span> Name <span class="op">{</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>      Name(COUNTER<span class="op">.</span>fetch_add(<span class="dv">1</span><span class="op">,</span> <span class="pp">std::sync::atomic::Ordering::</span>Relaxed))</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">mod</span> binder <span class="op">{</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">pub</span> <span class="kw">struct</span> Binder<span class="op">&lt;</span>T<span class="op">&gt;{</span> <span class="co">// (2)</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>    name<span class="op">:</span> Name<span class="op">,</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>    body<span class="op">:</span> T</span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>  <span class="kw">impl</span> <span class="op">&lt;</span>T<span class="op">&gt;</span> Binder<span class="op">&lt;</span>T<span class="op">&gt;{</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>    <span class="co">/* (5)</span></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a><span class="co">    Correctness condition: `f` should only use its argument to construct the `T`.</span></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a><span class="co">    The name shouldn&#39;t be made to outlive `f` in any other way, e.g. by storing</span></span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a><span class="co">    it in a mutable variable.</span></span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a><span class="co">    */</span></span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a>    <span class="kw">pub</span> <span class="kw">fn</span> bind(f<span class="op">:</span> <span class="kw">impl</span> <span class="bu">FnOnce</span>(Name) <span class="op">-&gt;</span> T) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span> <span class="co">// (3)</span></span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a>      <span class="kw">use</span> <span class="kw">super</span><span class="pp">::name::</span>fresh<span class="op">;</span></span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a>      </span>
<span id="cb1-30"><a href="#cb1-30" aria-hidden="true" tabindex="-1"></a>      <span class="kw">let</span> name <span class="op">=</span> fresh()<span class="op">;</span> <span class="co">// (4)</span></span>
<span id="cb1-31"><a href="#cb1-31" aria-hidden="true" tabindex="-1"></a>      Binder<span class="op">{</span> name<span class="op">,</span> body<span class="op">:</span> f(name) <span class="op">}</span></span>
<span id="cb1-32"><a href="#cb1-32" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-33"><a href="#cb1-33" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-34"><a href="#cb1-34" aria-hidden="true" tabindex="-1"></a>    <span class="co">/* (6)</span></span>
<span id="cb1-35"><a href="#cb1-35" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-36"><a href="#cb1-36" aria-hidden="true" tabindex="-1"></a><span class="co">    Correctness condition: `f` should not &quot;leak&quot; its `Name` argument. After `f` has</span></span>
<span id="cb1-37"><a href="#cb1-37" aria-hidden="true" tabindex="-1"></a><span class="co">    returned, the name shouldn&#39;t be accessible outside the binder.</span></span>
<span id="cb1-38"><a href="#cb1-38" aria-hidden="true" tabindex="-1"></a><span class="co">    */</span></span>
<span id="cb1-39"><a href="#cb1-39" aria-hidden="true" tabindex="-1"></a>    <span class="kw">pub</span> <span class="kw">fn</span> unbind<span class="op">&lt;</span>R<span class="op">&gt;</span>(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> f<span class="op">:</span> <span class="kw">impl</span> <span class="bu">FnOnce</span>(<span class="op">&amp;</span>Name<span class="op">,</span> <span class="op">&amp;</span>T) <span class="op">-&gt;</span> R) <span class="op">-&gt;</span> R <span class="op">{</span></span>
<span id="cb1-40"><a href="#cb1-40" aria-hidden="true" tabindex="-1"></a>      f(<span class="op">&amp;</span><span class="kw">self</span><span class="op">.</span>name<span class="op">,</span> <span class="op">&amp;</span><span class="kw">self</span><span class="op">.</span>body)</span>
<span id="cb1-41"><a href="#cb1-41" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-42"><a href="#cb1-42" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb1-43"><a href="#cb1-43" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Names (1) are opaque and can be compared for equality.</p>
<p>A binder (2) is a pair of a name with some type <code>T</code>, within which the name is considered <em>bound</em>.</p>
<p><code>bind</code> (3) is the only way to create binders, which is also the only time new names are introduced (4).
Since the fields of <code>Binder</code> are hidden, every binder binds a unique name.</p>
<p>Binder introduction (<code>bind</code>) and elimination (<code>unbind</code>) come with correctness conditions (5) (6) that
prevent bound names from “escaping their scope”. Programs that follow these rules are
capture-avoiding by construction; any terms that are substituted under a binder will not contain the
name bound by that binder.</p>
<p>There’s more to add, such as <code>Clone</code> and <code>Eq</code> implementations for <code>Binder</code>. As I explain nominal
sets I’ll translate the important concepts to code, so that by the end we’ll have a decent
variable binding library.</p>
<h2 id="nominal-sets"><a href="#nominal-sets">Nominal sets</a></h2>
<p>Nominal sets<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a><sup>,</sup><a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a><sup>,</sup><a href="#fn4" class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a><sup>,</sup><a href="#fn5" class="footnote-ref" id="fnref5" role="doc-noteref"><sup>5</sup></a> is a theory of
names and name binding, intended to help with implementing and verifying programming languages. Its most
remarkable feature is an account of algebraic datatypes and recursion modulo <a href="https://stackoverflow.com/a/47762545/2884502">alpha
equivalence</a>. In practise, this gives an elegant way
to work with abstract syntax trees while being able to ignore any specific choice of names.</p>
<p>I like nominal sets as a formalism because they are a good example of how category theory can inform library design.</p>
<h3 id="names"><a href="#names">Names</a></h3>
<p>Names can be drawn from any <a href="https://mathworld.wolfram.com/CountablyInfinite.html">countably infinite</a> set. In the literature, this set is written as
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>𝔸</mi><annotation encoding="application/x-tex">\mathbb{A}</annotation></semantics></math> (for <strong>A</strong>tom). I’ll keep to this convention while explaining the math.</p>
<p>The only operation on names is equality comparison, which I’ll write as <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mover><mo>=</mo><mo accent="false">?</mo></mover><mi>b</mi></mrow><annotation encoding="application/x-tex">a \stackrel{?}{=} b</annotation></semantics></math>.</p>
<h3 id="permutations"><a href="#permutations">Permutations</a></h3>
<p>A theory that deals with alpha equivalence needs a notion of “renaming variables”. Nominal sets uses
<a href="https://en.wikipedia.org/wiki/Permutation">permutations</a> of names.</p>
<p>A permutation of names (from here on, just “a permutation”) is a bijection on names. I’ll write
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Π</mi><annotation encoding="application/x-tex">\Pi</annotation></semantics></math> for the set of permutations, and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>π</mi><annotation encoding="application/x-tex">\pi</annotation></semantics></math> for any particular permutation.
Being functions, permutations are used by <em>applying</em> them to names, written <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\pi(a)</annotation></semantics></math>.
A permutation
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>π</mi><annotation encoding="application/x-tex">\pi</annotation></semantics></math> is “finite” when a finite set of atoms <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>a</mi><annotation encoding="application/x-tex">a</annotation></semantics></math> satisfies <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi>a</mi></mrow><annotation encoding="application/x-tex">\pi(a) \neq a</annotation></semantics></math>.</p>
<p>The fundamental permutation is the swapping of two names, written <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(a \; b)</annotation></semantics></math>. <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(a \; b)</annotation></semantics></math> is
the bijection mapping <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>a</mi><annotation encoding="application/x-tex">a</annotation></semantics></math> to <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>b</mi><annotation encoding="application/x-tex">b</annotation></semantics></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>b</mi><annotation encoding="application/x-tex">b</annotation></semantics></math> to <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>a</mi><annotation encoding="application/x-tex">a</annotation></semantics></math>, and any other name to itself.
Every finite permutation can be
decomposed into a sequence of swaps
(<a id="proof-1-link" href="nominal-sets-proofs#proof-1">A.1</a>).</p>
<p>In Rust I represent (finite) permutations using a <code>HashMap</code>. Applying takes keys to values, and any names not
in the <code>HashMap</code> are mapped to themselves. In other words, the <code>HashMap</code> represents a
permutation <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>π</mi><annotation encoding="application/x-tex">\pi</annotation></semantics></math> by storing a pair <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(x, \pi(x))</annotation></semantics></math> for
each <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>x</mi><annotation encoding="application/x-tex">x</annotation></semantics></math> where <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi>x</mi></mrow><annotation encoding="application/x-tex">\pi(x) \neq x</annotation></semantics></math>.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">mod</span> permutation <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">use</span> <span class="kw">super</span><span class="pp">::name::</span>Name<span class="op">;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  <span class="at">#[</span>derive<span class="at">(</span><span class="bu">Debug</span><span class="op">,</span> <span class="bu">Clone</span><span class="at">)]</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">pub</span> <span class="kw">struct</span> Permutation(HashMap<span class="op">&lt;</span>Name<span class="op">,</span> Name<span class="op">&gt;</span>)<span class="op">;</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">impl</span> Permutation <span class="op">{</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">pub</span> <span class="kw">fn</span> swap(a<span class="op">:</span> Name<span class="op">,</span> b<span class="op">:</span> Name) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Self</span>(<span class="pp">HashMap::</span>from([(a<span class="op">,</span> b)<span class="op">,</span> (b<span class="op">,</span> a)]))</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">pub</span> <span class="kw">fn</span> apply(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> name<span class="op">:</span> <span class="op">&amp;</span>Name) <span class="op">-&gt;</span> Name <span class="op">{</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>      <span class="kw">self</span><span class="op">.</span>get(name)<span class="op">.</span>copied()<span class="op">.</span>unwrap_or(<span class="op">*</span>name)</span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span></code></pre></div>
<p>Permutations form a <a href="https://en.wikipedia.org/wiki/Group_(mathematics)">group</a>. The identity
(<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>ι</mi><annotation encoding="application/x-tex">\iota</annotation></semantics></math>) is the identity function. Multiplication (<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>∘</mi><annotation encoding="application/x-tex">\circ</annotation></semantics></math>) is function composition. Every
permutation <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>π</mi><annotation encoding="application/x-tex">\pi</annotation></semantics></math> has an inverse <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><annotation encoding="application/x-tex">\pi^{-1}</annotation></semantics></math> (because they’re bijections).</p>
<p>In the code I call the multiplication function <code>after</code> so it’s easier to remember the order of the
permutations.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>    <span class="kw">pub</span> <span class="kw">fn</span> id() <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>      Permutation(<span class="pp">HashMap::</span>new())</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">pub</span> <span class="kw">fn</span> after(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> other<span class="op">:</span> <span class="op">&amp;</span><span class="dt">Self</span>) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>      <span class="kw">let</span> <span class="kw">mut</span> permutation <span class="op">=</span> other</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>          <span class="op">.</span>iter()</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>          <span class="op">.</span>map(<span class="op">|</span>(key<span class="op">,</span> value)<span class="op">|</span> (<span class="op">*</span>key<span class="op">,</span> <span class="kw">self</span><span class="op">.</span>apply(value)))</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>          <span class="op">.</span><span class="pp">collect::</span><span class="op">&lt;</span>HashMap<span class="op">&lt;</span>Name<span class="op">,</span> Name<span class="op">&gt;&gt;</span>()<span class="op">;</span> <span class="co">// (1)</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>      </span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>      permutation<span class="op">.</span>extend(<span class="kw">self</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>          <span class="op">.</span>iter()</span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>          <span class="op">.</span>filter(<span class="op">|</span>(key<span class="op">,</span> value)<span class="op">|</span> <span class="op">{</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>            <span class="cf">if</span> other<span class="op">.</span>contains(key) <span class="op">{</span> </span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>              <span class="cn">None</span> </span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>            <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span> </span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a>              <span class="cn">Some</span>((key<span class="op">,</span> value)) </span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a>            <span class="op">}</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a>          <span class="op">}</span>))<span class="op">;</span> <span class="co">// (2)</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a>      </span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a>      Permutation(permutation)</span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">pub</span> <span class="kw">fn</span> inverse(<span class="op">&amp;</span><span class="kw">self</span>) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a>      Permutation(<span class="kw">self</span><span class="op">.</span>iter()<span class="op">.</span>map(<span class="op">|</span>(key<span class="op">,</span> value)<span class="op">|</span> (<span class="op">*</span>value<span class="op">,</span> <span class="op">*</span>key))<span class="op">.</span>collect())</span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span></code></pre></div>
<p><code>after</code>, acting on <code>HashMap</code>s under the hood, needs a more clever definition than I
first expected. The final permutation <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>π</mi><mi>f</mi></msub><mo>∘</mo><msub><mi>π</mi><mi>g</mi></msub></mrow><annotation encoding="application/x-tex">\pi_f \circ \pi_g</annotation></semantics></math> is constructed in two parts. The first
part (1) computes <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>π</mi><mi>f</mi></msub><mo stretchy="false" form="prefix">(</mo><msub><mi>π</mi><mi>g</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\pi_f(\pi_g(x))</annotation></semantics></math> for all <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>x</mi><annotation encoding="application/x-tex">x</annotation></semantics></math> where <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>π</mi><mi>g</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi>x</mi></mrow><annotation encoding="application/x-tex">\pi_g(x) \neq x</annotation></semantics></math>. The second part (2)
computes <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>π</mi><mi>f</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\pi_f(x)</annotation></semantics></math> for all <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>x</mi><annotation encoding="application/x-tex">x</annotation></semantics></math> where <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>π</mi><mi>g</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>x</mi></mrow><annotation encoding="application/x-tex">\pi_g(x) = x</annotation></semantics></math>. For these values, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>π</mi><mi>f</mi></msub><mo stretchy="false" form="prefix">(</mo><msub><mi>π</mi><mi>g</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>=</mo><msub><mi>π</mi><mi>f</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\pi_f(\pi_g(x)) =
\pi_f(x)</annotation></semantics></math>. The first time I wrote this function, I mistakenly thought the first part would be enough.</p>
<p>Names are aren’t the only thing that can be affected by a permutation. “Applying” a permutation
generalises to other sets as the <a href="https://mathworld.wolfram.com/GroupAction.html">action</a> of
permutations on those sets. Permutations can act on a set <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>X</mi><annotation encoding="application/x-tex">X</annotation></semantics></math> when there exists a function
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>α</mi><mi>X</mi></msub><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mi mathvariant="normal">Π</mi><mo>×</mo><mi>X</mi><mo>→</mo><mi>X</mi></mrow><annotation encoding="application/x-tex">\alpha_X \; : \; \Pi \times X \rightarrow X</annotation></semantics></math>
satisfying the following properties:</p>
<ol type="1">
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>∀</mo><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><msub><mi>α</mi><mi>X</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>ι</mi><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>x</mi></mrow><annotation encoding="application/x-tex">\forall x. \; \alpha_X(\iota, x) = x</annotation></semantics></math> (identity)</li>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>∀</mo><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><msub><mi>α</mi><mi>X</mi></msub><mo stretchy="false" form="prefix">(</mo><msub><mi>π</mi><mn>1</mn></msub><mo>∘</mo><msub><mi>π</mi><mn>2</mn></msub><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><msub><mi>α</mi><mi>X</mi></msub><mo stretchy="false" form="prefix">(</mo><msub><mi>π</mi><mn>1</mn></msub><mo>,</mo><msub><mi>α</mi><mi>X</mi></msub><mo stretchy="false" form="prefix">(</mo><msub><mi>π</mi><mn>2</mn></msub><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\forall x. \; \alpha_X(\pi_1 \circ \pi_2, x) = \alpha_X(\pi_1, \alpha_X(\pi_2, x))</annotation></semantics></math> (composition)</li>
</ol>
<p>Instead of writing <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>α</mi><mi>X</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\alpha_X(\pi, x)</annotation></semantics></math> for a specific permutation action, I’ll use the notation <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo>⋅</mo><mi>x</mi></mrow><annotation encoding="application/x-tex">\pi \cdot x</annotation></semantics></math>.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>  <span class="co">/*</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="co">  Laws:</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="co">  </span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="co">  * `forall x. x.permute_by(Permutation::id()) == x` (identity)</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="co">  * `forall x. x.permute_by(f.after(g)) == x.permute_by(g).permute_by(f)` (composition)</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="co">  </span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="co">  */</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">pub</span> <span class="kw">trait</span> Permutable <span class="op">{</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> permute_by(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> permutation<span class="op">:</span> <span class="op">&amp;</span>Permutation) <span class="op">-&gt;</span> <span class="dt">Self</span><span class="op">;</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span></code></pre></div>
<p>Permutations trivially act on names: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo>⋅</mo><mi>a</mi><mo>=</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\pi \cdot a = \pi(a)</annotation></semantics></math>.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>  <span class="kw">impl</span> Permutable <span class="cf">for</span> Name <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> permute_by(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> permutation<span class="op">:</span> <span class="op">&amp;</span>Permutation) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>      permutation<span class="op">.</span>apply(<span class="kw">self</span>)</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span></code></pre></div>
<p>Permutations also trivially act on themselves: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>π</mi><mi>f</mi></msub><mo>⋅</mo><msub><mi>π</mi><mi>g</mi></msub><mo>=</mo><msub><mi>π</mi><mi>f</mi></msub><mo>∘</mo><msub><mi>π</mi><mi>g</mi></msub></mrow><annotation encoding="application/x-tex">\pi_f \cdot \pi_g = \pi_f \circ \pi_g</annotation></semantics></math>.</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>  <span class="kw">impl</span> Permutable <span class="cf">for</span> Permutation <span class="op">{</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> permute_by(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> permutation<span class="op">:</span> <span class="op">&amp;</span>Permutation) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>      permutation<span class="op">.</span>after(<span class="kw">self</span>)</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span></code></pre></div>
<p>Permutations act on pairs element-wise: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>,</mo><mi>π</mi><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\pi \cdot (x, y) = (\pi \cdot x, \pi \cdot y)</annotation></semantics></math>.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>  <span class="kw">impl</span> <span class="op">&lt;</span>A<span class="op">:</span> Permutable<span class="op">,</span> B<span class="op">:</span> Permutable<span class="op">&gt;</span> Permutable <span class="cf">for</span> (A<span class="op">,</span> B) <span class="op">{</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> permute_by(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> permutation<span class="op">:</span> <span class="op">&amp;</span>Permutation) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>      (<span class="kw">self</span><span class="op">.</span><span class="dv">0</span><span class="op">.</span>permute_by(permutation)<span class="op">,</span> <span class="kw">self</span><span class="op">.</span><span class="dv">1</span><span class="op">.</span>permute_by(permutation))</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span></code></pre></div>
<p>And similarly for sums: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo>⋅</mo><msub><mtext mathvariant="normal">in</mtext><mi>L</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><msub><mtext mathvariant="normal">in</mtext><mi>L</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo>∧</mo><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><msub><mtext mathvariant="normal">in</mtext><mi>R</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><msub><mtext mathvariant="normal">in</mtext><mi>R</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\pi \cdot \text{in}_L(x) =
\text{in}_L(\pi \cdot x) \; \land \; \pi \cdot \text{in}_R(y) =
\text{in}_R(\pi \cdot y)</annotation></semantics></math>.</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>  <span class="kw">impl</span> <span class="op">&lt;</span>A<span class="op">:</span> Permutable<span class="op">,</span> B<span class="op">:</span> Permutable<span class="op">&gt;</span> Permutable <span class="cf">for</span> <span class="pp">either::</span>Either<span class="op">&lt;</span>A<span class="op">,</span> B<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> permute_by(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> permutation<span class="op">:</span> <span class="op">&amp;</span>Permutation) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>      <span class="kw">use</span> <span class="pp">either::</span>Either<span class="op">;</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>      <span class="cf">match</span> <span class="kw">self</span> <span class="op">{</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>        Left(a) <span class="op">=&gt;</span> Left(a<span class="op">.</span>permute_by(permutation))<span class="op">,</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>        Right(b) <span class="op">=&gt;</span> Right(b<span class="op">.</span>permute_by(permutation))</span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span></code></pre></div>
<p>On a more Rust-specific note, heap allocation is <code>Permutable</code> because it’s essentially a
single-element product:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>  <span class="kw">impl</span> <span class="op">&lt;</span>A<span class="op">&gt;</span> Permutable <span class="cf">for</span> <span class="dt">Box</span><span class="op">&lt;</span>A<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> permute_by(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> permutation<span class="op">:</span> <span class="op">&amp;</span>Permutation) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>      <span class="kw">let</span> inner <span class="op">=</span> <span class="kw">self</span><span class="op">.</span>as_ref()<span class="op">.</span>permute_by(permutation)<span class="op">;</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Box</span><span class="pp">::</span>new(inner)</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="co">// mod permutation</span></span></code></pre></div>
<h4 id="permutations-on-functions"><a href="#permutations-on-functions">Permutations on functions</a></h4>
<p>Permutations can also act on functions: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(\pi \cdot f)(x) = \pi \cdot f(\pi^{-1} \cdot x)</annotation></semantics></math>. For my purposes this is only important in theory, so I won’t
implement it in Rust. This definition is derived from the requirement that permutations distribute over function application: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\pi
\cdot f(x) = (\pi \cdot f)(\pi \cdot x)</annotation></semantics></math>.</p>
<h3 id="support"><a href="#support">Support</a></h3>
<p>A set of names <em>supports</em> a value when the value “depends” on those names. Here’s the formal definition:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mi>𝒫</mi><mo stretchy="false" form="prefix">(</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">)</mo><mo>×</mo><mi>X</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">supports</mtext><mo>=</mo><mo stretchy="false" form="prefix">{</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>∈</mo><mi>𝒫</mi><mo stretchy="false" form="prefix">(</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">)</mo><mo>,</mo><mspace width="0.278em"></mspace><mi>x</mi><mo>∈</mo><mi>X</mi><mo>,</mo><mspace width="0.278em"></mspace><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>=</mo><mi>x</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="postfix">}</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{supports} \; : \; \mathcal{P}(\mathbb{A}) \times X
\\
\text{supports} =
\{ \;
(\bar{a}, x) \; | \; 
\bar{a} \in \mathcal{P}(\mathbb{A}), \;
x \in X, \;
\forall \pi. \; (\forall a \in \bar{a}. \; \pi(a) = a) \implies
\pi \cdot x = x 
\; \}
\end{array}
</annotation></semantics></math></p>
<p>In English: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi></mrow><annotation encoding="application/x-tex">\bar{a} \; \text{supports} \; x</annotation></semantics></math> when all permutations that keep the elements of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mover><mi>a</mi><mo accent="true">‾</mo></mover><annotation encoding="application/x-tex">\bar{a}</annotation></semantics></math> the same
(<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>∀</mo><mi>a</mi><mo>∈</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\forall a \in \bar{a}. \; \pi(a) = a)</annotation></semantics></math> also keep <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>x</mi><annotation encoding="application/x-tex">x</annotation></semantics></math>
the same (<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>=</mo><mi>x</mi></mrow><annotation encoding="application/x-tex">\pi \cdot x = x</annotation></semantics></math>).</p>
<p>For example, every name must support itself: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>a</mi></mrow><annotation encoding="application/x-tex">\{a\} \; \text{supports} \; a</annotation></semantics></math>
(<a id="proof-2-link" href="nominal-sets-proofs#proof-2">A.2</a>).
More importantly, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>∃</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mo>≠</mo><mi>a</mi><mspace width="0.278em"></mspace><mo>∧</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">{</mo><mi>b</mi><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>a</mi></mrow><annotation encoding="application/x-tex">\exists b. \; b \neq a \; \land \; \{b\} \; \text{supports} \; a</annotation></semantics></math> is false
(<a id="proof-3-link" href="nominal-sets-proofs#proof-3">A.3</a>).</p>
<p>Pairs are supported element-wise:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo>⇔</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo>∧</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>y</mi></mrow><annotation encoding="application/x-tex">
\bar{a}  \; \text{supports} \; (x, y) \iff \bar{a} \; \text{supports} \; x
\land \bar{a} \; \text{supports} \; y
</annotation></semantics></math></p>
<p>And sums variant-wise:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><msub><mtext mathvariant="normal">in</mtext><mi>L</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>⇔</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><msub><mtext mathvariant="normal">in</mtext><mi>R</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo>⇔</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>y</mi></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\bar{a} \; \text{supports} \; \text{in}_L(x) \iff \bar{a} \; \text{supports} \; x
\\
\bar{a} \;
\text{supports} \; \text{in}_R(y) \iff \bar{a} \; \text{supports} \; y
\end{array}
</annotation></semantics></math></p>
<p>Functions have a permutation action, and therefore the notion of support also applies to them.</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>f</mi><mo>⇔</mo></mtd><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo>=</mo><mi>f</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"></mtd><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo>∀</mo><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"></mtd><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo>∀</mo><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{ll}
\bar{a} \; \text{supports} \; f \iff &amp; \forall \pi. \; (\forall a \in \bar{a}. \; \pi(a) = a)
\implies \pi \cdot f = f
\\
&amp; \forall \pi. \; (\forall a \in \bar{a}. \; \pi(a) = a) 
\implies \forall x. \; (\pi \cdot f)(x) = f(x)
\\
&amp; \forall \pi. \; (\forall a \in \bar{a}. \; \pi(a) = a) 
\implies \forall x. \; \pi \cdot f(\pi^{-1} \cdot x) = f(x)
\end{array}
</annotation></semantics></math></p>
<h4 id="minimal-support"><a href="#minimal-support">Minimal support</a></h4>
<p>The definition of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtext mathvariant="normal">supports</mtext><annotation encoding="application/x-tex">\text{supports}</annotation></semantics></math> is a bit “loose”, because it allows names that don’t occur in a value
to support said value. For example, for names <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>a</mi><annotation encoding="application/x-tex">a</annotation></semantics></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>b</mi><annotation encoding="application/x-tex">b</annotation></semantics></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo>,</mo><mi>b</mi><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>a</mi></mrow><annotation encoding="application/x-tex">\{a,b\} \; \text{supports} \; a</annotation></semantics></math>
(<a id="proof-4-link" href="nominal-sets-proofs#proof-4">A.4</a>).</p>
<p>The notion of <em>minimal</em> support tightens this up. The minimal support of a value consists of only
the names the value <em>actually</em> depends on. <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mover><mi>a</mi><mo accent="true">‾</mo></mover><annotation encoding="application/x-tex">\bar{a}</annotation></semantics></math> is the minimal support of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>x</mi><annotation encoding="application/x-tex">x</annotation></semantics></math> when it is a subset of all other sets that support <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>x</mi><annotation encoding="application/x-tex">x</annotation></semantics></math>:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><msub><mtext mathvariant="normal">supports</mtext><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mi>𝒫</mi><mo stretchy="false" form="prefix">(</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">)</mo><mo>×</mo><mi>X</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><msub><mtext mathvariant="normal">supports</mtext><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub><mo>=</mo><mo stretchy="false" form="prefix">{</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>∈</mo><mi>𝒫</mi><mo stretchy="false" form="prefix">(</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">)</mo><mo>,</mo><mspace width="0.278em"></mspace><mi>x</mi><mo>∈</mo><mi>X</mi><mo>,</mo><mspace width="0.278em"></mspace><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo>,</mo><mo>∀</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mover><mi>x</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>⊆</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mo stretchy="false" form="postfix">}</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{supports}_{min} \; : \; \mathcal{P}(\mathbb{A}) \times X
\\
\text{supports}_{min} =
\{ \;
(\bar{a}, x) \; | \; \bar{a} \in \mathcal{P}(\mathbb{A}), \; x \in X, \;
\bar{a} \; \text{supports} \; x, \forall \bar{x}. \; \bar{x} \; \text{supports} \; x \implies
\bar{a} \subseteq \bar{x} 
\; \}
\end{array}
</annotation></semantics></math></p>
<p>I can say <em>the</em> minimal support, because it’s unique for every value
(<a id="proof-5-link" href="nominal-sets-proofs#proof-5">A.5</a>). From now on I’ll just refer to “the minimal support” as “the support”, and use a “minimal
support” function instead of the <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mtext mathvariant="normal">supports</mtext><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub><annotation encoding="application/x-tex">\text{supports}_{min}</annotation></semantics></math> relation:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">support</mtext><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mi>X</mi><mo>→</mo><mi>𝒫</mi><mo stretchy="false" form="prefix">(</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> such that </mtext><mspace width="0.333em"></mspace></mrow><mo>∀</mo><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><msub><mtext mathvariant="normal">supports</mtext><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{support} \; : \; X \rightarrow \mathcal{P}(\mathbb{A}) \text{ such that } \forall x. \; \text{support}(x) \; \text{supports}_{min} \; x
\end{array}
</annotation></semantics></math></p>
<p>Putting it all into code:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">mod</span> support <span class="op">{</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">use</span> <span class="kw">super</span><span class="pp">::name::</span>Name<span class="op">;</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">pub</span> <span class="kw">trait</span> Supported<span class="op">:</span> Permutable <span class="op">{</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>    <span class="co">/// Computes the minimal support of a value.</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> support(<span class="op">&amp;</span><span class="kw">self</span>) <span class="op">-&gt;</span> HashSet<span class="op">&lt;</span>Name<span class="op">&gt;</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">impl</span> Supported <span class="cf">for</span> Name <span class="op">{</span></span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> support(<span class="op">&amp;</span><span class="kw">self</span>) <span class="op">-&gt;</span> HashSet<span class="op">&lt;</span>Name<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a>      <span class="pp">HashSet::</span>from([<span class="op">*</span><span class="kw">self</span>])</span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">impl</span> <span class="op">&lt;</span>A<span class="op">:</span> Supported<span class="op">,</span> B<span class="op">:</span> Supported<span class="op">&gt;</span> Supported <span class="cf">for</span> (A<span class="op">,</span> B) <span class="op">{</span></span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> support(<span class="op">&amp;</span><span class="kw">self</span>) <span class="op">-&gt;</span> HashSet<span class="op">&lt;</span>Name<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a>      <span class="kw">self</span><span class="op">.</span><span class="dv">0</span><span class="op">.</span>support()<span class="op">.</span><span class="kw">union</span>(<span class="kw">self</span><span class="op">.</span><span class="dv">1</span><span class="op">.</span>support())<span class="op">.</span>collect()</span>
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-19"><a href="#cb10-19" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb10-20"><a href="#cb10-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-21"><a href="#cb10-21" aria-hidden="true" tabindex="-1"></a>  <span class="kw">impl</span> <span class="op">&lt;</span>A<span class="op">:</span> Supported<span class="op">,</span> B<span class="op">:</span> Supported<span class="op">&gt;</span> Supported <span class="cf">for</span> <span class="pp">either::</span>Either<span class="op">&lt;</span>A<span class="op">,</span> B<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb10-22"><a href="#cb10-22" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> support(<span class="op">&amp;</span><span class="kw">self</span>) <span class="op">-&gt;</span> HashSet<span class="op">&lt;</span>Name<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb10-23"><a href="#cb10-23" aria-hidden="true" tabindex="-1"></a>      <span class="kw">use</span> <span class="pp">either::</span>Either<span class="op">;</span></span>
<span id="cb10-24"><a href="#cb10-24" aria-hidden="true" tabindex="-1"></a>      <span class="cf">match</span> <span class="kw">self</span> <span class="op">{</span></span>
<span id="cb10-25"><a href="#cb10-25" aria-hidden="true" tabindex="-1"></a>        Left(a) <span class="op">=&gt;</span> a<span class="op">.</span>support()<span class="op">,</span></span>
<span id="cb10-26"><a href="#cb10-26" aria-hidden="true" tabindex="-1"></a>        Right(b) <span class="op">=&gt;</span> b<span class="op">.</span>support()</span>
<span id="cb10-27"><a href="#cb10-27" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb10-28"><a href="#cb10-28" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-29"><a href="#cb10-29" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb10-30"><a href="#cb10-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-31"><a href="#cb10-31" aria-hidden="true" tabindex="-1"></a>  <span class="kw">impl</span> <span class="op">&lt;</span>A<span class="op">&gt;</span> Supported <span class="cf">for</span> <span class="dt">Box</span><span class="op">&lt;</span>A<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb10-32"><a href="#cb10-32" aria-hidden="true" tabindex="-1"></a>    support(<span class="op">&amp;</span><span class="kw">self</span>) <span class="op">-&gt;</span> HashSet<span class="op">&lt;</span>Name<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb10-33"><a href="#cb10-33" aria-hidden="true" tabindex="-1"></a>      <span class="kw">self</span><span class="op">.</span>as_ref()<span class="op">.</span>support()</span>
<span id="cb10-34"><a href="#cb10-34" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-35"><a href="#cb10-35" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb10-36"><a href="#cb10-36" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h4 id="the-support-of-a-function"><a href="#the-support-of-a-function">The support of a function</a></h4>
<p>I think of the support of a function as the set of names that have been “captured” by the function.
The identity function returns its argument and does nothing else, so it’s supported by the empty set
(<a id="proof-6-link" href="nominal-sets-proofs#proof-6">A.6</a>).
A function that compares its two name arguments and nothing else
(like <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext mathvariant="normal">cmp</mtext><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mover><mo>=</mo><mo accent="false">?</mo></mover><mi>b</mi></mrow><annotation encoding="application/x-tex">\text{cmp}(a, b) = a \stackrel{?}{=} b</annotation></semantics></math>)
is also supported by the empty set
(<a id="proof-7-link" href="nominal-sets-proofs#proof-7">A.7</a>).
A function that references names other than its arguments has those names in its support. For
example, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>a</mi><annotation encoding="application/x-tex">a</annotation></semantics></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>b</mi><annotation encoding="application/x-tex">b</annotation></semantics></math> must be in the support of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext mathvariant="normal">iffy</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mrow><mtext mathvariant="normal">if </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><mover><mo>=</mo><mo accent="false">?</mo></mover><mi>x</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> then </mtext><mspace width="0.333em"></mspace></mrow><mi>b</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> else </mtext><mspace width="0.333em"></mspace></mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">\text{iffy}(x) = \text{if } a \stackrel{?}{=} x \text{ then } b
\text{ else } x</annotation></semantics></math>
(<a id="proof-8-link" href="nominal-sets-proofs#proof-8">A.8</a>).</p>
<h3 id="freshness"><a href="#freshness">Freshness</a></h3>
<p>A name <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>a</mi><annotation encoding="application/x-tex">a</annotation></semantics></math> is fresh for a value <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>x</mi><annotation encoding="application/x-tex">x</annotation></semantics></math> (written <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi></mrow><annotation encoding="application/x-tex">a \; \# \; x</annotation></semantics></math>) when <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mo>∉</mo><msub><mtext mathvariant="normal">support</mtext><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">a \notin \text{support}_{min}(x)</annotation></semantics></math>.</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">mod</span> support <span class="op">{</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>  <span class="op">...</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">pub</span> <span class="kw">fn</span> fresh_for<span class="op">&lt;</span>T<span class="op">:</span> Supported<span class="op">&gt;</span>(name<span class="op">:</span> <span class="op">&amp;</span>Name<span class="op">,</span> value<span class="op">:</span> <span class="op">&amp;</span>T) <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">!</span>value<span class="op">.</span>support()<span class="op">.</span>contains(name)</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Since atoms are drawn from a countably infinite set, we take as an axiom that for any set of atoms there exists an atom that is fresh for them:
<span id="axiom-choose-a-fresh-name">
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>∀</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mo>∈</mo><mi>𝒫</mi><mo stretchy="false" form="prefix">(</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mo>∃</mo><mi>a</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mover><mi>x</mi><mo accent="true">‾</mo></mover></mrow><annotation encoding="application/x-tex">\forall \bar{x} \in \mathcal{P}(\mathbb{A}). \; \exists a. \; a \; \# \; \bar{x}</annotation></semantics></math>
</span>.
This is known as the “choose-a-fresh-name” principle, and it’s what motivates the global number generator I use for
<code>Name</code>s.</p>
<p>Some useful properties involving freshness:</p>
<ul>
<li><p>Swapping fresh names does nothing: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mo>∧</mo><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mi>x</mi></mrow><annotation encoding="application/x-tex">a \; \# \; x \land b \; \# \; x \implies (a \; b) \cdot x = x</annotation></semantics></math>
(<a id="proof-9-link" href="nominal-sets-proofs#proof-9">A.9</a>).</p></li>
<li><p>Freshness “distributes” across functions: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>f</mi><mo>∧</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">a \; \# \; f \land a \; \# \; x \implies a \; \# \; f(x)</annotation></semantics></math>
(<a id="proof-10-link" href="nominal-sets-proofs#proof-10">A.10</a>).</p></li>
</ul>
<h3 id="name-binding"><a href="#name-binding">Name binding</a></h3>
<p>Name binding (written <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mi>X</mi></mrow><annotation encoding="application/x-tex">[\mathbb{A}]X</annotation></semantics></math>) is the <a href="https://en.wikipedia.org/wiki/Equivalence_class">quotient</a><a href="#fn6" class="footnote-ref" id="fnref6" role="doc-noteref"><sup>6</sup></a> of name-value pairs
by a sort of “generalised alpha equivalence”. Elements of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mi>X</mi></mrow><annotation encoding="application/x-tex">[\mathbb{A}]X</annotation></semantics></math> are written as
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi></mrow><annotation encoding="application/x-tex">\langle a \rangle x</annotation></semantics></math>.</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mi>X</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>𝔸</mi><mo>×</mo><mi>X</mi><mo stretchy="false" form="postfix">)</mo><mi>/</mi><msub><mo>∼</mo><mi>α</mi></msub></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><msub><mo>∼</mo><mi>α</mi></msub><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>𝔸</mi><mo>×</mo><mi>X</mi><mo stretchy="false" form="postfix">)</mo><mo>×</mo><mo stretchy="false" form="prefix">(</mo><mi>𝔸</mi><mo>×</mo><mi>X</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><msub><mo>∼</mo><mi>α</mi></msub><mspace width="0.278em"></mspace><mo>=</mo><mo stretchy="false" form="prefix">{</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>,</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mo>,</mo><msup><mi>x</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mi>a</mi><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo>∈</mo><mi>𝔸</mi><mo>,</mo><mspace width="0.278em"></mspace><mi>x</mi><mo>,</mo><msup><mi>x</mi><mo>′</mo></msup><mo>∈</mo><mi>X</mi><mo>,</mo><mspace width="0.278em"></mspace><mo>∃</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mi>x</mi><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo>,</mo><msup><mi>x</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo>∧</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mo stretchy="false" form="postfix">}</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
[\mathbb{A}]X = (\mathbb{A} \times X) / \sim_\alpha
\\ \; \\
\sim_\alpha \; : \; (\mathbb{A} \times X) \times (\mathbb{A} \times X)
\\
\sim_\alpha \; = \{ \; 
((a, x), (a&#39;, x&#39;)) \; | \;
a, a&#39; \in \mathbb{A}, \;
x, x&#39; \in X, \;
\exists b. \; 
b \; \# \; (a, x, a&#39;, x&#39;)
\; \land \;
(a \; b) \cdot x = (a&#39; \; b) \cdot x&#39;
\; \}
\end{array}
</annotation></semantics></math></p>
<p>Two name binders are considered equal when renaming their bound name to a completely
fresh name makes their bodies equal.</p>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mi>X</mi></mrow><annotation encoding="application/x-tex">[\mathbb{A}]X</annotation></semantics></math> is the <code>Binder</code> type that I defined at the beginning. Now we have tools to
define equality on <code>Binder</code>s:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span> <span class="op">&lt;</span>T<span class="op">:</span> <span class="bu">PartialEq</span><span class="op">&gt;</span> <span class="bu">PartialEq</span> <span class="cf">for</span> Binder<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">fn</span> eq(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> other<span class="op">:</span> <span class="op">&amp;</span><span class="dt">Self</span>) <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">use</span> <span class="kw">super</span><span class="pp">::name::</span>fresh<span class="op">;</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> b <span class="op">=</span> fresh()<span class="op">;</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">self</span><span class="op">.</span>body<span class="op">.</span>permute_by(<span class="pp">Permutation::</span>swap(<span class="kw">self</span><span class="op">.</span>name<span class="op">,</span> b)) <span class="op">==</span> </span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>        other<span class="op">.</span>body<span class="op">.</span>permute_by(<span class="pp">Permutation::</span>swap(other<span class="op">.</span>name<span class="op">,</span> b))</span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span> <span class="op">&lt;</span>T<span class="op">:</span> <span class="bu">Eq</span><span class="op">&gt;</span> <span class="bu">Eq</span> <span class="cf">for</span> Binder<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">{}</span></span></code></pre></div>
<p>Since every binder binds a unique name and binders are immutable, there is a fast path for equality: two binders that
bind the same name are actually the same binder.</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span> <span class="op">&lt;</span>T<span class="op">:</span> <span class="bu">PartialEq</span><span class="op">&gt;</span> <span class="bu">PartialEq</span> <span class="cf">for</span> Binder<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">fn</span> eq(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> other<span class="op">:</span> <span class="op">&amp;</span><span class="dt">Self</span>) <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">use</span> <span class="kw">super</span><span class="pp">::name::</span>fresh<span class="op">;</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="kw">self</span><span class="op">.</span>name <span class="op">==</span> other<span class="op">.</span>name <span class="op">{</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>      <span class="cn">true</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>      <span class="kw">let</span> b <span class="op">=</span> fresh()<span class="op">;</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>      <span class="kw">self</span><span class="op">.</span>body<span class="op">.</span>permute_by(<span class="pp">Permutation::</span>swap(<span class="kw">self</span><span class="op">.</span>name<span class="op">,</span> b)) <span class="op">==</span> </span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a>          other<span class="op">.</span>body<span class="op">.</span>permute_by(<span class="pp">Permutation::</span>swap(other<span class="op">.</span>name<span class="op">,</span> b))</span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span> <span class="op">&lt;</span>T<span class="op">:</span> <span class="bu">Eq</span><span class="op">&gt;</span> <span class="bu">Eq</span> <span class="cf">for</span> Binder<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">{}</span></span></code></pre></div>
<p>Name binding has a permutation action and a finite support.</p>
<p>Permutation action: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo>⋅</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><mi>π</mi><mo>⋅</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\pi \cdot \langle a \rangle x = \langle \pi \cdot a \rangle (\pi \cdot x)</annotation></semantics></math></p>
<div class="sourceCode" id="cb14"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span> <span class="op">&lt;</span>T<span class="op">:</span> Permutable<span class="op">&gt;</span> Permutable <span class="cf">for</span> Binder<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">fn</span> permute_by(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> permutation<span class="op">:</span> <span class="op">&amp;</span>Permutation) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>    Binder<span class="op">{</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>      name<span class="op">:</span> name<span class="op">.</span>permute_by(permutation)<span class="op">,</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>      body<span class="op">:</span> body<span class="op">.</span>permute_by(permutation)</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The support of a name binder excludes its bound name: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo>=</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo></mrow><annotation encoding="application/x-tex">\text{support} (\langle a \rangle x) \; = \text{support}(x) - \{ a \}</annotation></semantics></math> (<a id="proof-11-link" href="nominal-sets-proofs#proof-11">A.11</a>).
Freshness is the negation of this: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mspace width="0.278em"></mspace><mo>⇔</mo><mspace width="0.278em"></mspace><mi>b</mi><mo>=</mo><mi>a</mi><mspace width="0.278em"></mspace><mo>∨</mo><mspace width="0.278em"></mspace><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi></mrow><annotation encoding="application/x-tex">b \; \# \; \langle a \rangle x \; \iff \; b = a \; \lor \; b \; \# \; x</annotation></semantics></math> (<a id="proof-12-link" href="nominal-sets-proofs#proof-12">A.12</a>).</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span> <span class="op">&lt;</span>T<span class="op">:</span> Supported<span class="op">&gt;</span> Supported <span class="cf">for</span> Binder<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">fn</span> support(<span class="op">&amp;</span><span class="kw">self</span>) <span class="op">-&gt;</span> HashSet<span class="op">&lt;</span>Name<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> <span class="kw">mut</span> support <span class="op">=</span> <span class="kw">self</span><span class="op">.</span>body<span class="op">.</span>support()<span class="op">;</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>    support<span class="op">.</span>remove(<span class="op">&amp;</span><span class="kw">self</span><span class="op">.</span>name)<span class="op">;</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>    support</span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>We can now define <code>Clone</code> for binders. It respects the property that every <code>Binder</code> binds a unique name.</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span> <span class="bu">Clone</span> <span class="cf">for</span> Binder<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">fn</span> clone(<span class="op">&amp;</span><span class="kw">self</span>) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">self</span><span class="op">.</span>unbind(<span class="op">|</span>name<span class="op">,</span> body<span class="op">|</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>      <span class="pp">Binder::</span>new(<span class="op">|</span>new_name<span class="op">|</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>        body<span class="op">.</span>permute_by(<span class="pp">Permutation::</span>swap(name<span class="op">,</span> new_name))</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>      )</span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a>    )</span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>When reasoning about binder equality, it’s often inconvenient to find an atom <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mi>x</mi><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo>,</mo><msup><mi>x</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">b \; \# \; (a, x, a&#39;, x&#39;)</annotation></semantics></math>
such that <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mrow><annotation encoding="application/x-tex">(a \; b) \cdot x = (a&#39; \; b) \cdot x&#39;</annotation></semantics></math>. When that’s the case, we prove an
equivalent property: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>∀</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mi>x</mi><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo>,</mo><msup><mi>x</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mrow><annotation encoding="application/x-tex">\forall b. \; b \; \# \; (a, x, a&#39;, x&#39;) \implies (a \; b) \cdot x = (a&#39; \; b) \cdot x&#39;</annotation></semantics></math>
(<a id="proof-13-link" href="nominal-sets-proofs#proof-13">A.13</a>).
Any specific fresh atom is interchangeable with all fresh atoms that satisfy the same conditions.</p>
<h3 id="the-category-of-nominal-sets"><a href="#the-category-of-nominal-sets">The category of nominal sets</a></h3>
<p>Any set <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>X</mi><annotation encoding="application/x-tex">X</annotation></semantics></math> with a permutation action <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>π</mi><annotation encoding="application/x-tex">\pi</annotation></semantics></math> is called a <em>nominal set</em> when for each
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>∈</mo><mi>X</mi></mrow><annotation encoding="application/x-tex">x \in X</annotation></semantics></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>x</mi><annotation encoding="application/x-tex">x</annotation></semantics></math> has a finite, minimal support.</p>
<p>Nominal sets are the objects of a category (<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtext mathvariant="normal">Nom</mtext><annotation encoding="application/x-tex">\text{Nom}</annotation></semantics></math>) whose arrows are functions that preserve permutation
actions: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>∀</mo><mi>π</mi><mo>,</mo><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\forall \pi, x. \; f(\pi \cdot x) = \pi \cdot f(x)</annotation></semantics></math>. These are called
<a href="https://en.wikipedia.org/wiki/Equivariant_map">equivariant</a> functions. One important fact about equivariant functions
is that they’re supported by the empty set (<a id="proof-14-link" href="nominal-sets-proofs#proof-14">A.14</a>).</p>
<p>The identity arrows are just the identity function on each nominal set. The identity function is
equivariant (<a id="proof-15-link" href="nominal-sets-proofs#proof-15">A.15</a>). Composition of arrows is the composition
of equivariant functions, which preserves equivariance
(<a id="proof-16-link" href="nominal-sets-proofs#proof-16">A.16</a>). I’ll use <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><annotation encoding="application/x-tex">\rightarrow_{Nom}</annotation></semantics></math> for <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtext mathvariant="normal">Nom</mtext><annotation encoding="application/x-tex">\text{Nom}</annotation></semantics></math> arrows,
e.g. <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>Y</mi></mrow><annotation encoding="application/x-tex">X \rightarrow_{Nom} Y</annotation></semantics></math>.</p>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtext mathvariant="normal">Nom</mtext><annotation encoding="application/x-tex">\text{Nom}</annotation></semantics></math> has a <a href="https://en.wikipedia.org/wiki/Terminal_object">terminal object</a>, which is the
singleton set (<a id="proof-17-link" href="nominal-sets-proofs#proof-17">A.17</a>).</p>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtext mathvariant="normal">Nom</mtext><annotation encoding="application/x-tex">\text{Nom}</annotation></semantics></math> has <a href="https://en.wikipedia.org/wiki/Product_(category_theory)">products</a>, which
are pairs of nominal sets with an element-wise permutation action, because introduction and elimination of pairs is equivariant
(<a id="proof-18-link" href="nominal-sets-proofs#proof-18">A.18</a>).</p>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtext mathvariant="normal">Nom</mtext><annotation encoding="application/x-tex">\text{Nom}</annotation></semantics></math> has <a href="https://en.wikipedia.org/wiki/Coproduct">coproducts</a>, which is the normal
disjoint union on sets with an element-wise permutation action, because introduction and elimination of coproducts is equivariant
(<a id="proof-19-link" href="nominal-sets-proofs#proof-19">A.19</a>).</p>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtext mathvariant="normal">Nom</mtext><annotation encoding="application/x-tex">\text{Nom}</annotation></semantics></math> has <a href="https://en.wikipedia.org/wiki/Exponential_object">exponentials</a>, in the form of
finitely supported functions between nominal sets (<a id="proof-20-link" href="nominal-sets-proofs#proof-20">A.20</a>).</p>
<p>These facts have two important consequences for programmers:</p>
<ol type="1">
<li><p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtext mathvariant="normal">Nom</mtext><annotation encoding="application/x-tex">\text{Nom}</annotation></semantics></math> is a <a href="https://en.wikipedia.org/wiki/Cartesian_closed_category">cartesian closed category</a>, which means it contains the lambda calculus. You can create a “nominal programming language” that has first class names<a href="#fn7" class="footnote-ref" id="fnref7" role="doc-noteref"><sup>7</sup></a>.</p></li>
<li><p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtext mathvariant="normal">Nom</mtext><annotation encoding="application/x-tex">\text{Nom}</annotation></semantics></math> can express <a href="https://en.wikipedia.org/wiki/Initial_algebra">initial algebra semantics</a>, which means your “nominal programming language” can have “nominal algebraic datatypes”.</p></li>
</ol>
<p>In a sense <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtext mathvariant="normal">Nom</mtext><annotation encoding="application/x-tex">\text{Nom}</annotation></semantics></math> is fundamentally compatible with programming, and I think that’s why nominal sets are such a good inspiration for a library.</p>
<h3 id="some-adjunctions"><a href="#some-adjunctions">Some adjunctions</a></h3>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mo stretchy="false" form="prefix">(</mo><mi>−</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">[\mathbb{A}]({-})</annotation></semantics></math> is an endofunctor on <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtext mathvariant="normal">Nom</mtext><annotation encoding="application/x-tex">\text{Nom}</annotation></semantics></math> with the following action on
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtext mathvariant="normal">Nom</mtext><annotation encoding="application/x-tex">\text{Nom}</annotation></semantics></math>-arrows:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mi>Y</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
[\mathbb{A}](f) \; : \; [\mathbb{A}] X \rightarrow_{Nom} [\mathbb{A}] Y
\\
[\mathbb{A}](f)(\langle a \rangle x) = \langle a \rangle f(x)
\end{array}
</annotation></semantics></math></p>
<p>This means <code>Binder</code> has a <code>map</code> method:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">mod</span> binder <span class="op">{</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">impl</span> <span class="op">&lt;</span>T<span class="op">&gt;</span> Binder<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">...</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>    <span class="co">/** Correctness condition: `f` should not capture any [`Name`]s. When this is the case, we have `binder.map(f).map(g) == binder.map(|x| g(f(x)))`.</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a><span class="co">    */</span></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">pub</span> <span class="kw">fn</span> map<span class="op">&lt;</span>B<span class="op">&gt;</span>(<span class="kw">self</span><span class="op">,</span> f<span class="op">:</span> <span class="kw">impl</span> <span class="bu">FnOnce</span>(T) <span class="op">-&gt;</span> B) <span class="op">-&gt;</span> Binder<span class="op">&lt;</span>B<span class="op">&gt;</span> <span class="op">{</span> <span class="co">// (7)</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a>      Binder<span class="op">{</span> name<span class="op">:</span> <span class="kw">self</span><span class="op">.</span>name<span class="op">,</span> body<span class="op">:</span> f(<span class="kw">self</span><span class="op">.</span>body) <span class="op">}</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mo stretchy="false" form="prefix">(</mo><mi>−</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">[\mathbb{A}]({-})</annotation></semantics></math> has left and right <a href="https://en.wikipedia.org/wiki/Adjoint_functors">adjoints</a> that induce a nice API for working with <code>Binder</code>s.</p>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mo stretchy="false" form="prefix">(</mo><mi>−</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">[\mathbb{A}]({-})</annotation></semantics></math> is right adjoint to the functor <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow></mrow><mo>−</mo><mi>*</mi><mspace width="0.278em"></mspace><mi>𝔸</mi></mrow><annotation encoding="application/x-tex">{}- * \; \mathbb{A}</annotation></semantics></math> arising from the following
nominal set: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>X</mi><mo>*</mo><mi>𝔸</mi><mo>=</mo><mo stretchy="false" form="prefix">{</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mi>x</mi><mo>∈</mo><mi>X</mi><mo>,</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="postfix">}</mo></mrow><annotation encoding="application/x-tex">X * \mathbb{A} = \{ \; (x, a) \; | \; x \in X, a \; \# \; x  \;\}</annotation></semantics></math> (<a id
="proof-22-link" href="nominal-sets-proofs#proof-22">A.22</a>).</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mfrac><mrow><mi>X</mi><mo>*</mo><mi>𝔸</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>Y</mi></mrow><mrow><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mi>Y</mi></mrow></mfrac><annotation encoding="application/x-tex">
\frac{
X * \mathbb{A} \rightarrow_{Nom} Y
}{
X \rightarrow_{Nom} [\mathbb{A}] Y
}
</annotation></semantics></math></p>
<p><br></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">bind</mtext><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>X</mi><mo>*</mo><mi>𝔸</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>Y</mi><mo stretchy="false" form="postfix">)</mo><mo>→</mo><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mi>Y</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">bind</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mtext mathvariant="normal">for some</mtext><mspace width="0.278em"></mspace><mi>a</mi><mi>#</mi><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><msup><mtext mathvariant="normal">bind</mtext><mrow><mi>−</mi><mn>1</mn></mrow></msup><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mi>Y</mi><mo stretchy="false" form="postfix">)</mo><mo>→</mo><mi>X</mi><mo>*</mo><mi>𝔸</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>Y</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><msup><mtext mathvariant="normal">bind</mtext><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mrow><mi>𝑜</mi><mi>𝑚</mi><mi>𝑖</mi><mi>𝑡</mi><mi>𝑡</mi><mi>𝑒</mi><mi>𝑑</mi></mrow></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{bind} \; : \; (X * \mathbb{A} \rightarrow_{Nom} Y) \rightarrow
X \rightarrow_{Nom} [\mathbb{A}] Y
\\
\text{bind}(f)(x) = \langle a \rangle f(x, a) \;\;\; \text{for some} \; a \# x
\\ \; \\
\text{bind}^{-1} \; : \; (X \rightarrow_{Nom} [\mathbb{A}] Y) \rightarrow
X * \mathbb{A} \rightarrow_{Nom} Y
\\
\text{bind}^{-1}(f)(x) = \mathit{omitted}
\end{array}
</annotation></semantics></math></p>
<p>The “rightward” direction of the adjunction (<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtext mathvariant="normal">bind</mtext><annotation encoding="application/x-tex">\text{bind}</annotation></semantics></math>) describes a way to create binders. It says that you can create a binder using a name that has never been seen before. This corresponds to the <code>bind</code> function from <a href="#names-and-binders">Names and Binders</a>.</p>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mo stretchy="false" form="prefix">(</mo><mi>−</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">[\mathbb{A}]({-})</annotation></semantics></math> is left adjoint to this functor:
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>R</mi><mo stretchy="false" form="prefix">(</mo><mi>Y</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">{</mo><mspace width="0.278em"></mspace><mi>f</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mi>f</mi><mo>∈</mo><msup><mi>Y</mi><mi>𝔸</mi></msup><mo>,</mo><mspace width="0.278em"></mspace><mo>∀</mo><mi>a</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="postfix">}</mo></mrow><annotation encoding="application/x-tex">R(Y) = \{ \; f \; | \; f \in Y^{\mathbb{A}}, \; \forall a. \; a \; \# \; f(a) \;
\}</annotation></semantics></math> (<a id
="proof-23-link" href="nominal-sets-proofs#proof-23">A.23</a>).</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mfrac><mrow><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>Y</mi></mrow><mrow><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>R</mi><mo stretchy="false" form="prefix">(</mo><mi>Y</mi><mo stretchy="false" form="postfix">)</mo></mrow></mfrac><annotation encoding="application/x-tex">
\frac{
[\mathbb{A}] X \rightarrow_{Nom} Y
}{
X \rightarrow_{Nom} R(Y)
}
</annotation></semantics></math></p>
<p><br></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><msup><mtext mathvariant="normal">unbind</mtext><mrow><mi>−</mi><mn>1</mn></mrow></msup><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>Y</mi><mo stretchy="false" form="postfix">)</mo><mo>→</mo><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>R</mi><mo stretchy="false" form="prefix">(</mo><mi>Y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><msup><mtext mathvariant="normal">unbind</mtext><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>=</mo><mrow><mi>𝑜</mi><mi>𝑚</mi><mi>𝑖</mi><mi>𝑡</mi><mi>𝑡</mi><mi>𝑒</mi><mi>𝑑</mi></mrow></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">unbind</mtext><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>R</mi><mo stretchy="false" form="prefix">(</mo><mi>Y</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>→</mo><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>Y</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">unbind</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{unbind}^{-1} \; : \; ([\mathbb{A}] X \rightarrow_{Nom} Y) \rightarrow X \rightarrow_{Nom} R(Y)
\\
\text{unbind}^{-1} = \mathit{omitted}
\\ \; \\
\text{unbind} \; : \; (X \rightarrow_{Nom} R(Y)) \rightarrow [\mathbb{A}] X \rightarrow_{Nom} Y
\\
\text{unbind}(f)(\langle a \rangle x) = f(a)(x)
\end{array}
</annotation></semantics></math></p>
<p>The “leftward” direction of this adjunction (<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtext mathvariant="normal">unbind</mtext><annotation encoding="application/x-tex">\text{unbind}</annotation></semantics></math>) describes how to consume binders.
You can consume a binder, accessing both its body and bound name, using a function that doesn’t
“leak” the name. This corresponds to <code>unbind</code> in <a href="#names-and-binders">Names and Binders</a>.</p>
<h2 id="showing-off"><a href="#showing-off">Showing off</a></h2>
<p>Having gone through the theoretical justifications for the design of the <code>Binder</code> type, let’s examine
some of its benefits in practise.</p>
<h3 id="alpha-equivalence"><a href="#alpha-equivalence">Alpha equivalence</a></h3>
<p>Given implementations of <code>Permutable</code> and <code>Supported</code>, an abstract syntax tree can derive an <code>Eq</code>
instance that implements alpha equivalence:</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>deriving<span class="at">(</span><span class="bu">PartialEq</span><span class="op">,</span> <span class="bu">Eq</span><span class="op">,</span> <span class="bu">Clone</span><span class="at">)]</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> Expr <span class="op">{</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>  Var(Name)<span class="op">,</span></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>  Lam(Binder<span class="op">&lt;</span><span class="dt">Box</span><span class="op">&lt;</span>Expr<span class="op">&gt;&gt;</span>)<span class="op">,</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>  App(<span class="dt">Box</span><span class="op">&lt;</span>Expr<span class="op">&gt;,</span> <span class="dt">Box</span><span class="op">&lt;</span>Expr<span class="op">&gt;</span>)</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span> Permutable <span class="cf">for</span> Expr <span class="op">{</span></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">fn</span> permute_by(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> permutation<span class="op">:</span> <span class="op">&amp;</span>Permutation) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a>    <span class="cf">match</span> <span class="kw">self</span> <span class="op">{</span></span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a>      <span class="pp">Expr::</span>Var(name) <span class="op">=&gt;</span> <span class="pp">Expr::</span>Var(name<span class="op">.</span>permute_by(permutation))<span class="op">,</span></span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a>      <span class="pp">Expr::</span>Lam(binder) <span class="op">=&gt;</span> <span class="pp">Expr::</span>Lam(binder<span class="op">.</span>permute_by(permutation))<span class="op">,</span></span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a>      <span class="pp">Expr::</span>App(left<span class="op">,</span> right) <span class="op">=&gt;</span> <span class="pp">Expr::</span>App(</span>
<span id="cb18-14"><a href="#cb18-14" aria-hidden="true" tabindex="-1"></a>        left<span class="op">.</span>permute_by(permutation)<span class="op">,</span></span>
<span id="cb18-15"><a href="#cb18-15" aria-hidden="true" tabindex="-1"></a>        right<span class="op">.</span>permute_by(permutation)</span>
<span id="cb18-16"><a href="#cb18-16" aria-hidden="true" tabindex="-1"></a>      )</span>
<span id="cb18-17"><a href="#cb18-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb18-18"><a href="#cb18-18" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-19"><a href="#cb18-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb18-20"><a href="#cb18-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-21"><a href="#cb18-21" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span> Supported <span class="cf">for</span> Expr <span class="op">{</span></span>
<span id="cb18-22"><a href="#cb18-22" aria-hidden="true" tabindex="-1"></a>  <span class="kw">fn</span> support(<span class="op">&amp;</span><span class="kw">self</span>) <span class="op">-&gt;</span> HashSet<span class="op">&lt;</span>Name<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb18-23"><a href="#cb18-23" aria-hidden="true" tabindex="-1"></a>    <span class="cf">match</span> <span class="kw">self</span> <span class="op">{</span></span>
<span id="cb18-24"><a href="#cb18-24" aria-hidden="true" tabindex="-1"></a>      <span class="pp">Expr::</span>Var(name) <span class="op">=&gt;</span> <span class="pp">HashSet::</span>from([name])<span class="op">,</span></span>
<span id="cb18-25"><a href="#cb18-25" aria-hidden="true" tabindex="-1"></a>      <span class="pp">Expr::</span>Lam(binder) <span class="op">=&gt;</span> binder<span class="op">.</span>support()<span class="op">,</span></span>
<span id="cb18-26"><a href="#cb18-26" aria-hidden="true" tabindex="-1"></a>      <span class="pp">Expr::</span>App(left<span class="op">,</span> right) <span class="op">=&gt;</span> <span class="op">{</span></span>
<span id="cb18-27"><a href="#cb18-27" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> <span class="kw">mut</span> support <span class="op">=</span> left<span class="op">.</span>support()<span class="op">;</span></span>
<span id="cb18-28"><a href="#cb18-28" aria-hidden="true" tabindex="-1"></a>        support<span class="op">.</span>extend(right<span class="op">.</span>support())<span class="op">;</span></span>
<span id="cb18-29"><a href="#cb18-29" aria-hidden="true" tabindex="-1"></a>        support</span>
<span id="cb18-30"><a href="#cb18-30" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb18-31"><a href="#cb18-31" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb18-32"><a href="#cb18-32" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-33"><a href="#cb18-33" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Which means the following are true:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="co">// (\x -&gt; x) =_{alpha} (\y -&gt; y)</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="pp">assert_eq!</span>(</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>  <span class="pp">Expr::</span>Lam(<span class="pp">Binder::</span>bind(<span class="op">|</span>x<span class="op">|</span> <span class="dt">Box</span><span class="pp">::</span>new(<span class="pp">Expr::</span>Var(x))))<span class="op">,</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>  <span class="pp">Expr::</span>Lam(<span class="pp">Binder::</span>bind(<span class="op">|</span>y<span class="op">|</span> <span class="dt">Box</span><span class="pp">::</span>new(<span class="pp">Expr::</span>Var(y))))</span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>)</span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a><span class="co">// (\x y -&gt; x) =_{alpha} (\y x -&gt; y)</span></span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a><span class="pp">assert_eq!</span>(</span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a>  <span class="pp">Expr::</span>Lam(<span class="pp">Binder::</span>bind(<span class="op">|</span>x<span class="op">|</span></span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Box</span><span class="pp">::</span>new(<span class="pp">Expr::</span>Lam(<span class="pp">Binder::</span>Bind(<span class="op">|</span>y<span class="op">|</span></span>
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Box</span><span class="pp">::</span>new(<span class="pp">Expr::</span>Var(x))</span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a>    ))))</span>
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a>  )<span class="op">,</span></span>
<span id="cb19-14"><a href="#cb19-14" aria-hidden="true" tabindex="-1"></a>  <span class="pp">Expr::</span>Lam(<span class="pp">Binder::</span>bind(<span class="op">|</span>y<span class="op">|</span></span>
<span id="cb19-15"><a href="#cb19-15" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Box</span><span class="pp">::</span>new(<span class="pp">Expr::</span>Lam(<span class="pp">Binder::</span>Bind(<span class="op">|</span>x<span class="op">|</span></span>
<span id="cb19-16"><a href="#cb19-16" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Box</span><span class="pp">::</span>new(<span class="pp">Expr::</span>Var(y))</span>
<span id="cb19-17"><a href="#cb19-17" aria-hidden="true" tabindex="-1"></a>    ))))</span>
<span id="cb19-18"><a href="#cb19-18" aria-hidden="true" tabindex="-1"></a>  )<span class="op">,</span></span>
<span id="cb19-19"><a href="#cb19-19" aria-hidden="true" tabindex="-1"></a>)</span>
<span id="cb19-20"><a href="#cb19-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-21"><a href="#cb19-21" aria-hidden="true" tabindex="-1"></a><span class="co">// (\x y -&gt; x) !=_{alpha} (\x y -&gt; y)</span></span>
<span id="cb19-22"><a href="#cb19-22" aria-hidden="true" tabindex="-1"></a><span class="pp">assert_neq!</span>(</span>
<span id="cb19-23"><a href="#cb19-23" aria-hidden="true" tabindex="-1"></a>  <span class="pp">Expr::</span>Lam(<span class="pp">Binder::</span>bind(<span class="op">|</span>x<span class="op">|</span></span>
<span id="cb19-24"><a href="#cb19-24" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Box</span><span class="pp">::</span>new(<span class="pp">Expr::</span>Lam(<span class="pp">Binder::</span>Bind(<span class="op">|</span>y<span class="op">|</span></span>
<span id="cb19-25"><a href="#cb19-25" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Box</span><span class="pp">::</span>new(<span class="pp">Expr::</span>Var(x))</span>
<span id="cb19-26"><a href="#cb19-26" aria-hidden="true" tabindex="-1"></a>    ))))</span>
<span id="cb19-27"><a href="#cb19-27" aria-hidden="true" tabindex="-1"></a>  )<span class="op">,</span></span>
<span id="cb19-28"><a href="#cb19-28" aria-hidden="true" tabindex="-1"></a>  <span class="pp">Expr::</span>Lam(<span class="pp">Binder::</span>bind(<span class="op">|</span>x<span class="op">|</span></span>
<span id="cb19-29"><a href="#cb19-29" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Box</span><span class="pp">::</span>new(<span class="pp">Expr::</span>Lam(<span class="pp">Binder::</span>Bind(<span class="op">|</span>y<span class="op">|</span></span>
<span id="cb19-30"><a href="#cb19-30" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Box</span><span class="pp">::</span>new(<span class="pp">Expr::</span>Var(y))</span>
<span id="cb19-31"><a href="#cb19-31" aria-hidden="true" tabindex="-1"></a>    ))))</span>
<span id="cb19-32"><a href="#cb19-32" aria-hidden="true" tabindex="-1"></a>  )<span class="op">,</span></span>
<span id="cb19-33"><a href="#cb19-33" aria-hidden="true" tabindex="-1"></a>)</span></code></pre></div>
<h3 id="capture-avoiding-substitution"><a href="#capture-avoiding-substitution">Capture-avoiding substitution</a></h3>
<p>Substituting a value for a name is defined by the <code>Subst</code> trait:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">mod</span> subst <span class="op">{</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">pub</span> <span class="kw">trait</span> Subst<span class="op">&lt;</span>V<span class="op">&gt;:</span> Permutable <span class="op">{</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> subst(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> name<span class="op">:</span> <span class="op">&amp;</span>Name<span class="op">,</span> value<span class="op">:</span> <span class="op">&amp;</span>V) <span class="op">-&gt;</span> <span class="dt">Self</span></span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span></code></pre></div>
<p>It has all the usual implementations:</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a>  <span class="kw">impl</span> <span class="op">&lt;</span>A<span class="op">:</span> Subst<span class="op">&lt;</span>V<span class="op">&gt;,</span> B<span class="op">:</span> Subst<span class="op">&lt;</span>V<span class="op">&gt;&gt;</span> Subst<span class="op">&lt;</span>V<span class="op">&gt;</span> <span class="cf">for</span> (A<span class="op">,</span> B) <span class="op">{</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> subst(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> name<span class="op">:</span> <span class="op">&amp;</span>Name<span class="op">,</span> value<span class="op">:</span> <span class="op">&amp;</span>V) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>      (<span class="kw">self</span><span class="op">.</span><span class="dv">0</span><span class="op">.</span>subst(name<span class="op">,</span> value)<span class="op">,</span> <span class="kw">self</span><span class="op">.</span><span class="dv">1</span><span class="op">.</span>subst(name<span class="op">,</span> value))</span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> </span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">impl</span> <span class="op">&lt;</span>A<span class="op">:</span> Subst<span class="op">&lt;</span>V<span class="op">&gt;,</span> B<span class="op">:</span> Subst<span class="op">&lt;</span>V<span class="op">&gt;&gt;</span> Subst<span class="op">&lt;</span>V<span class="op">&gt;</span> <span class="cf">for</span> <span class="pp">either::</span>Either<span class="op">&lt;</span>A<span class="op">,</span> B<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> subst(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> name<span class="op">:</span> <span class="op">&amp;</span>Name<span class="op">,</span> value<span class="op">:</span> <span class="op">&amp;</span>V) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb21-9"><a href="#cb21-9" aria-hidden="true" tabindex="-1"></a>      <span class="kw">use</span> <span class="pp">either::</span>Either<span class="op">;</span></span>
<span id="cb21-10"><a href="#cb21-10" aria-hidden="true" tabindex="-1"></a>      <span class="cf">match</span> <span class="kw">self</span> <span class="op">{</span></span>
<span id="cb21-11"><a href="#cb21-11" aria-hidden="true" tabindex="-1"></a>        Left(a) <span class="op">=&gt;</span> Left(a<span class="op">.</span>subst(name<span class="op">,</span> value))<span class="op">,</span></span>
<span id="cb21-12"><a href="#cb21-12" aria-hidden="true" tabindex="-1"></a>        Right(b) <span class="op">=&gt;</span> Right(b<span class="op">.</span>subst(name<span class="op">,</span> value))</span>
<span id="cb21-13"><a href="#cb21-13" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb21-14"><a href="#cb21-14" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb21-15"><a href="#cb21-15" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> </span>
<span id="cb21-16"><a href="#cb21-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-17"><a href="#cb21-17" aria-hidden="true" tabindex="-1"></a>  <span class="kw">impl</span> <span class="op">&lt;</span>T<span class="op">:</span> Subst<span class="op">&lt;</span>V<span class="op">&gt;&gt;</span> Subst<span class="op">&lt;</span>V<span class="op">&gt;</span> <span class="cf">for</span> <span class="dt">Box</span><span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb21-18"><a href="#cb21-18" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> subst(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> name<span class="op">:</span> <span class="op">&amp;</span>Name<span class="op">,</span> value<span class="op">:</span> <span class="op">&amp;</span>V) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb21-19"><a href="#cb21-19" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Box</span><span class="pp">::</span>new(<span class="kw">self</span><span class="op">.</span>as_ref()<span class="op">.</span>subst(name<span class="op">,</span> value))</span>
<span id="cb21-20"><a href="#cb21-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb21-21"><a href="#cb21-21" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span></code></pre></div>
<p>And the <code>Binder</code> implementation clones the binder before substituting into the body, which
guarantees capture-avoidance by binding a name that hasn’t occurred in <code>name</code> or <code>value</code>.</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a>  <span class="kw">use</span> <span class="kw">super</span><span class="pp">::binder::</span>Binder<span class="op">;</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">impl</span> <span class="op">&lt;</span>T<span class="op">:</span> Subst<span class="op">&lt;</span>V<span class="op">&gt;&gt;</span> Subst<span class="op">&lt;</span>V<span class="op">&gt;</span> <span class="cf">for</span> Binder<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> subst(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> name<span class="op">:</span> <span class="op">&amp;</span>Name<span class="op">,</span> value<span class="op">:</span> <span class="op">&amp;</span>V) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>      <span class="kw">self</span><span class="op">.</span>clone()<span class="op">.</span>map(<span class="op">|</span>body<span class="op">|</span> body<span class="op">.</span>subst(name<span class="op">,</span> value))</span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="co">// mod subst</span></span></code></pre></div>
<p>Now capture-avoiding substitution can be defined for <code>Expr</code>:</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span> Subst<span class="op">&lt;</span>Expr<span class="op">&gt;</span> <span class="cf">for</span> Expr <span class="op">{</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">fn</span> subst(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> name<span class="op">:</span> <span class="op">&amp;</span>Name<span class="op">,</span> value<span class="op">:</span> <span class="op">&amp;</span>Expr) <span class="op">-&gt;</span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">match</span> <span class="kw">self</span> <span class="op">{</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a>      <span class="pp">Expr::</span>Var(var) <span class="op">=&gt;</span> <span class="cf">if</span> var <span class="op">==</span> name <span class="op">{</span> </span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a>        value<span class="op">.</span>clone()</span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span> </span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a>        <span class="pp">Expr::</span>Var(var) </span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a>      <span class="op">},</span></span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a>      <span class="pp">Expr::</span>Lam(body) <span class="op">=&gt;</span> <span class="pp">Expr::</span>Lam(body<span class="op">.</span>subst(name<span class="op">,</span> value))<span class="op">,</span></span>
<span id="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a>      <span class="pp">Expr::</span>App(left<span class="op">,</span> right) <span class="op">=&gt;</span> <span class="pp">Expr::</span>App(</span>
<span id="cb23-11"><a href="#cb23-11" aria-hidden="true" tabindex="-1"></a>        left<span class="op">.</span>subst(name<span class="op">,</span> value)<span class="op">,</span></span>
<span id="cb23-12"><a href="#cb23-12" aria-hidden="true" tabindex="-1"></a>        right<span class="op">.</span>subst(name<span class="op">,</span> value)</span>
<span id="cb23-13"><a href="#cb23-13" aria-hidden="true" tabindex="-1"></a>      )</span>
<span id="cb23-14"><a href="#cb23-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb23-15"><a href="#cb23-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 id="final-thoughts"><a href="#final-thoughts">Final thoughts</a></h2>
<p>While the library I’ve sketched so far is <em>okay</em>, it’s not something I’d publish. Here are some outstanding issues, concerns, and questions:</p>
<ul>
<li><p>I don’t like the lack of support for mutability. Functions like <code>permute_by</code> and
<code>subst</code> end up rebuilding the value they’re acting on. This is a waste of time when I have exclusive
access to the value; I should be able to mutate the value in place and skip “reconstructing” the result.</p></li>
<li><p>The implementation of <code>PartialEq</code> for <code>Binder</code> is wasteful:</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> eq(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> other<span class="op">:</span> <span class="op">&amp;</span><span class="dt">Self</span>) <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">use</span> <span class="kw">super</span><span class="pp">::name::</span>fresh<span class="op">;</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span> b <span class="op">=</span> fresh()<span class="op">;</span></span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">self</span><span class="op">.</span>permute_by(<span class="pp">Permutation::</span>swap(<span class="kw">self</span><span class="op">.</span>name<span class="op">,</span> b)) <span class="op">==</span> </span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a>      other<span class="op">.</span>permute_by(<span class="pp">Permutation::</span>swap(other<span class="op">.</span>name<span class="op">,</span> b))</span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The function (immutably) permutes each argument, which amounts to cloning them. I should be able to
compare binders without cloning! What’s more, the structure is essentially walked from root to tip
once for each binder it contains. Comparison should be done a <em>single</em> downward pass.</p></li>
<li><p><code>Permutable</code>, <code>Supported</code>, and <code>Subst</code> for user-defined types are boilerplate. They should be automatically derived, or based on a single user-defined function that locates names in the user’s datatypes.</p></li>
<li><p>Should <code>Eq</code> actually implement alpha equivalence, or should I have a separate trait? I’m not sure how to implement <code>Eq</code> efficiently given its signature, and my intuition suggests <code>Eq</code> should be strict structural equality rather than including any quotienting.</p></li>
<li><p>Should the user be able to choose different <code>fresh</code> functions? This doesn’t really matter if <code>Eq</code> implements alpha equivalence, but if <code>Eq</code> is structural equivalence then it might be more convenient to use a different “name generator” for testing.</p></li>
</ul>
<p>You can follow my explorations at <a href="https://github.com/LightAndLight/binders.rs" class="uri">https://github.com/LightAndLight/binders.rs</a>.</p>
<h2 id="appendix-a-proofs"><a href="#appendix-a-proofs">Appendix A: Proofs</a></h2>
<p>See <a href="./nominal-sets-proofs">Nominal Sets: Appendix A (Proofs)</a>.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Let me know if (when?) I’m wrong about this!<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>Pitts, A. M. (2013). Nominal sets: Names and symmetry in computer science.
Cambridge University Press.<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3"><p>Pitts, A. M. (2003). Nominal logic, a first order theory of names and binding.
Information and computation, 186(2), 165-193.</p>
<p><a href="https://doi.org/10.1016/S0890-5401(03)00138-X" class="uri">https://doi.org/10.1016/S0890-5401(03)00138-X</a><a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4"><p>Pitts, A. M. (2006). Alpha-structural recursion and
induction. Journal of the ACM (JACM), 53(3), 459-506.</p>
<p><a href="https://doi.org/10.1145/1147954.1147961" class="uri">https://doi.org/10.1145/1147954.1147961</a><a href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn5"><p>Pitts, A. (2016). Nominal techniques. ACM SIGLOG News, 3(1), 57-72.</p>
<p><a href="https://doi.org/10.1145/2893582.2893594" class="uri">https://doi.org/10.1145/2893582.2893594</a><a href="#fnref5" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn6"><p>I found <a href="https://www.hedonisticlearning.com/posts/quotient-types-for-programmers.html">“Quotient Types for
Programmers”</a> very
helpful for understanding quotients.<a href="#fnref6" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn7"><p>Cheney, J. (2009). A simple nominal type theory. Electronic Notes
in Theoretical Computer Science, 228, 37-52.</p>
<p><a href="https://doi.org/10.1016/j.entcs.2008.12.115" class="uri">https://doi.org/10.1016/j.entcs.2008.12.115</a><a href="#fnref7" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
    ]]></content>
    
</entry>
<entry>
    <title>Nominal Sets: Appendix A (Proofs)</title>
    <link href="https://blog.ielliott.io/nominal-sets-proofs" />
    
    <id>https://blog.ielliott.io/nominal-sets-proofs</id>
    
    <published>2023-07-04T06:40:00Z</published>
    <updated>2023-07-04T06:40:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/nominal-sets-proofs"><![CDATA[<p>The proofs for my <a href="nominal-sets">Nominal Sets article</a>.</p>
]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/nominal-sets-proofs"><![CDATA[
      
      <p>Here are the proofs for my <a href="nominal-sets">Nominal Sets article</a>.
This was a personal exercise to improve my mathematical reasoning; I don’t expect anyone to read it.
That said, if you do find any mistakes then please let me know!</p>
<h2 id="proof-1"><a href="#proof-1">Proof 1</a></h2>
<p>Every finite permutation can be decomposed into a sequence of swaps.
<a href="nominal-sets#proof-1-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>a</mi><mn>1</mn></msub><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>a</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mi>.</mi><mi>.</mi><mi>.</mi><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>a</mi><mi>n</mi></msub><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>a</mi><mi>n</mi></msub><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> where </mtext><mspace width="0.333em"></mspace></mrow><msub><mi>a</mi><mi>i</mi></msub><mo>≠</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>a</mi><mi>i</mi></msub><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>a</mi><mi>j</mi></msub><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><msub><mi>a</mi><mi>j</mi></msub></mrow><annotation encoding="application/x-tex">
\forall \pi. \; \pi = (a_1 \; \pi(a_1)) \circ ... \circ (a_n \; \pi(a_n)) \text{ where } a_i \neq \pi(a_i) \neq \pi(a_j) \neq a_j
</annotation></semantics></math></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">Induction on </mtext><mspace width="0.333em"></mspace></mrow><mo stretchy="false" form="prefix">{</mo><mspace width="0.278em"></mspace><mi>x</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi>x</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="postfix">}</mo><mtext mathvariant="normal">:</mtext></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">case </mtext><mspace width="0.333em"></mspace></mrow><mo stretchy="false" form="prefix">{</mo><mspace width="0.278em"></mspace><mi>x</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi>x</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="postfix">}</mo><mo>=</mo><mi>∅</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mtext mathvariant="normal">trivial</mtext></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">case </mtext><mspace width="0.333em"></mspace></mrow><mo stretchy="false" form="prefix">{</mo><mspace width="0.278em"></mspace><mi>x</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi>x</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="postfix">}</mo><mo>=</mo><mi>S</mi><mo>∪</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> where </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><mo>∉</mo><mi>S</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mrow><mtext mathvariant="normal">assume </mtext><mspace width="0.333em"></mspace></mrow><mo>∀</mo><msup><mi>π</mi><mo>′</mo></msup><mi>.</mi><mspace width="0.278em"></mspace><msup><mi>π</mi><mo>′</mo></msup><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo>∧</mo><mo stretchy="false" form="prefix">{</mo><mspace width="0.278em"></mspace><msup><mi>π</mi><mo>′</mo></msup><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mi>b</mi><mo>∈</mo><mi>S</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><mo>⟹</mo><mspace width="0.278em"></mspace><msup><mi>π</mi><mo>′</mo></msup><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>a</mi><mn>1</mn></msub><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>a</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mi>.</mi><mi>.</mi><mi>.</mi><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>a</mi><mi>n</mi></msub><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>a</mi><mi>n</mi></msub><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mi>π</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mi>π</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><msup><mi>π</mi><mo>′</mo></msup><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mi>π</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><msup><mi>π</mi><mo>′</mo></msup><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mi>π</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><msup><mi>π</mi><mo>′</mo></msup><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mi>π</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> for </mtext><mspace width="0.333em"></mspace></mrow><mi>b</mi><mo>≠</mo><mi>a</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>a</mi><mn>1</mn></msub><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>a</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mi>.</mi><mi>.</mi><mi>.</mi><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>a</mi><mi>n</mi></msub><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>a</mi><mi>n</mi></msub><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">inductive hypothesis</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{Induction on } \{ \; x \; | \; \pi(x) \neq x \; \} \text{:}
\\
\text{case } \{ \; x \; | \; \pi(x) \neq x \; \} = \emptyset
\\
\; \; \; \; \text{trivial}
\\
\text{case } \{ \; x \; | \; \pi(x) \neq x \; \} = S \cup \{a\} \text{ where } a \notin S
\\
\; \; \; \; \text{assume } \forall \pi&#39;. \; \pi&#39;(a) = a \land \{ \; \pi&#39;(b) = \pi(b) \; | \; b \in S \; \}
\;
\implies
\;
\pi&#39; = (a_1 \; \pi(a_1)) \circ ... \circ (a_n \; \pi(a_n)) 
\\
\; \; \; \; \pi
\\
\; \; \; \; = (a \; \pi(a)) \circ (a \; \pi(a)) \circ \pi
\\
\; \; \; \; \; \; \; \; \pi&#39; = (a \; \pi(a)) \circ \pi
\\
\; \; \; \; \; \; \; \; \; \; \; \; \pi&#39;(a) = ((a \; \pi(a)) \circ \pi)(a) = (a \; \pi(a))(\pi(a)) = a
\\
\; \; \; \; \; \; \; \; \; \; \; \; \pi&#39;(b) = ((a \; \pi(a)) \circ \pi)(b) = (a \; \pi(a))(\pi(b)) = \pi(b) \text{ for } b \neq a
\\
\; \; \; \; = (a \; \pi(a)) \circ (a_1 \; \pi(a_1)) \circ ... \circ (a_n \; \pi(a_n)) \; (\text{inductive hypothesis})
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-2"><a href="#proof-2">Proof 2</a></h2>
<p>Every name must support itself: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>a</mi></mrow><annotation encoding="application/x-tex">\{a\} \; \text{supports} \; a</annotation></semantics></math>.
<a href="nominal-sets#proof-2-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="center" style="text-align: center"><mtable><mtr><mtd columnalign="left" style="text-align: left"></mtd><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mi>π</mi><mo>⋅</mo><mi>a</mi><mo>=</mo><mi>a</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo></mtd><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo>⟹</mo><mi>π</mi><mo>⋅</mo><mi>a</mi><mo>=</mo><mi>a</mi></mtd><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">singleton set</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo></mtd><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo>⟹</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi></mtd><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mrow><mtext mathvariant="normal">definition of </mtext><mspace width="0.333em"></mspace></mrow><mi>⋅</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable></mtd></mtr><mtr><mtd columnalign="center" style="text-align: center"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="center" style="text-align: center"><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo>⟹</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mtext mathvariant="normal">trivial</mtext></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{c}
\begin{array}{lll}
&amp; \forall \pi. \;
(\forall a \in \{a\}. \; \pi(a) = a) \implies \pi \cdot a = a
\\
= &amp; \forall \pi. \; \pi(a) = a \implies \pi \cdot a = a &amp; (\text{singleton set})
\\
= &amp; \forall \pi. \; \pi(a) = a \implies \pi(a) = a &amp; (\text{definition of } \cdot)
\end{array}
\\ \; \\
\forall \pi. \; \pi(a) = a \implies \pi(a) = a \;\;\;\; \text{trivial}
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-3"><a href="#proof-3">Proof 3</a></h2>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>∃</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mo>≠</mo><mi>a</mi><mspace width="0.278em"></mspace><mo>∧</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">{</mo><mi>b</mi><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>a</mi></mrow><annotation encoding="application/x-tex">\exists b. \; b \neq a \; \land \; \{b\} \; \text{supports} \; a</annotation></semantics></math> is false.
<a href="nominal-sets#proof-3-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="center" style="text-align: center"><mtable><mtr><mtd columnalign="left" style="text-align: left"></mtd><mtd columnalign="left" style="text-align: left"><mo>∃</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mo>≠</mo><mi>a</mi><mspace width="0.278em"></mspace><mo>∧</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">{</mo><mi>b</mi><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>a</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo></mtd><mtd columnalign="left" style="text-align: left"><mo>∃</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mo>≠</mo><mi>a</mi><mspace width="0.278em"></mspace><mo>∧</mo><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mo stretchy="false" form="prefix">{</mo><mi>b</mi><mo stretchy="false" form="postfix">}</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mi>π</mi><mo>⋅</mo><mi>a</mi><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo></mtd><mtd columnalign="left" style="text-align: left"><mo>∃</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mo>≠</mo><mi>a</mi><mspace width="0.278em"></mspace><mo>∧</mo><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>b</mi><mo>⟹</mo><mi>π</mi><mo>⋅</mo><mi>a</mi><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"></mtd></mtr></mtable></mtd></mtr><mtr><mtd columnalign="center" style="text-align: center"><mtable><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">assume </mtext><mspace width="0.333em"></mspace></mrow><mo>∃</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mo>≠</mo><mi>a</mi><mspace width="0.278em"></mspace><mo>∧</mo><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>b</mi><mo>⟹</mo><mi>π</mi><mo>⋅</mo><mi>a</mi><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">counterexample: </mtext><mspace width="0.333em"></mspace></mrow><mi>π</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>c</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>≠</mo><mi>b</mi><mo>≠</mo><mi>c</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>c</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>b</mi><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>c</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mrow><mtext mathvariant="normal">but </mtext><mspace width="0.333em"></mspace></mrow><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>c</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>c</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> — contradiction</mtext></mrow></mtd></mtr></mtable></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{c}
\begin{array}{lll}
&amp; \exists b. \; b \neq a \; \land \; \{b\} \; \text{supports} \; a
\\
= &amp; \exists b. \; b \neq a \; \land (\forall \pi. \; (\forall a \in \{b\}. \; \pi(a) = a) \implies \pi \cdot a = a)
\\
= &amp; \exists b. \; b \neq a \; \land (\forall \pi. \; \pi(b) = b \implies \pi \cdot a = a)
\\
\end{array}
\\
\begin{array}{l}
\text{assume } \exists b. \; b \neq a \; \land (\forall \pi. \; \pi(b) = b \implies \pi \cdot a = a)
\\
\text{counterexample: } \pi = (a \; c) \; (a \neq b \neq c)
\\
\; \; \; \; (a \; c)(b) = b \implies (a \; c)(a) = a
\\
\; \; \; \; \text{but } (a \; c)(a) = c \text{ --- contradiction}
\end{array}
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-4"><a href="#proof-4">Proof 4</a></h2>
<p>For names <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>a</mi><annotation encoding="application/x-tex">a</annotation></semantics></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>b</mi><annotation encoding="application/x-tex">b</annotation></semantics></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo>,</mo><mi>b</mi><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>a</mi></mrow><annotation encoding="application/x-tex">\{a,b\} \; \text{supports} \; a</annotation></semantics></math>.
<a href="nominal-sets#proof-4-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mtable><mtr><mtd columnalign="left" style="text-align: left"></mtd><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo>,</mo><mi>b</mi><mo stretchy="false" form="postfix">}</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mi>π</mi><mo>⋅</mo><mi>a</mi><mo>=</mo><mi>a</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo></mtd><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo>∧</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>b</mi><mo>⟹</mo><mi>π</mi><mo>⋅</mo><mi>a</mi><mo>=</mo><mi>a</mi></mtd><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">expand set</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo></mtd><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo>∧</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>b</mi><mo>⟹</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi></mtd><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mrow><mtext mathvariant="normal">definition of </mtext><mspace width="0.333em"></mspace></mrow><mi>⋅</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo>∧</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>b</mi><mo>⟹</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mtext mathvariant="normal">trivial</mtext></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\begin{array}{lll}
&amp; \forall \pi. \; (\forall a \in \{a, b\}. \; \pi(a) = a) \implies \pi \cdot a = a
\\
= &amp; \forall \pi. \; \pi(a) = a \land \pi(b) = b \implies \pi \cdot a = a &amp;
(\text{expand set})
\\
= &amp; \forall \pi. \; \pi(a) = a \land \pi(b) = b \implies \pi(a) = a &amp;
(\text{definition of } \cdot)
\end{array}
\\ \; \\
\forall \pi. \; \pi(a) = a \land \pi(b) = b \implies \pi(a) = a \;\;\;\;
\text{trivial}
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-5"><a href="#proof-5">Proof 5</a></h2>
<p>Uniqueness of minimal supports.
<a href="nominal-sets#proof-5-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><msub><mtext mathvariant="normal">supports</mtext><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub><mspace width="0.278em"></mspace><mi>x</mi><mo>∧</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><msub><mtext mathvariant="normal">supports</mtext><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>=</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtable><mtr><mtd columnalign="left" style="text-align: left"></mtd><mtd columnalign="left" style="text-align: left"><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><msub><mtext mathvariant="normal">supports</mtext><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub><mspace width="0.278em"></mspace><mi>x</mi><mo>∧</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><msub><mtext mathvariant="normal">supports</mtext><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo></mtd><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>∈</mo><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="prefix">(</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>∈</mo><mi>𝒫</mi><mo stretchy="false" form="prefix">(</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">)</mo><mo>,</mo><mspace width="0.278em"></mspace><mi>x</mi><mo>∈</mo><mi>X</mi><mo>,</mo><mspace width="0.278em"></mspace><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo>,</mo><mspace width="0.278em"></mspace><mo>∀</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mover><mi>x</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>⊆</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><mo>∧</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"></mtd><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>∈</mo><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="prefix">(</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>∈</mo><mi>𝒫</mi><mo stretchy="false" form="prefix">(</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">)</mo><mo>,</mo><mspace width="0.278em"></mspace><mi>x</mi><mo>∈</mo><mi>X</mi><mo>,</mo><mspace width="0.278em"></mspace><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo>,</mo><mspace width="0.278em"></mspace><mo>∀</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mover><mi>x</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>⊆</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">}</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo></mtd><mtd columnalign="left" style="text-align: left"><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mspace width="0.278em"></mspace><mo>∧</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mover><mi>x</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>⊆</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo>∧</mo><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"></mtd><mtd columnalign="left" style="text-align: left"><mover><mi>b</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mspace width="0.278em"></mspace><mo>∧</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mover><mi>x</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo>⊆</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"></mtd><mtd columnalign="left" style="text-align: left"><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mspace width="0.278em"></mspace><mo>∧</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mover><mi>x</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo>⊆</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo>⊆</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"></mtd><mtd columnalign="left" style="text-align: left"><mover><mi>b</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mspace width="0.278em"></mspace><mo>∧</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mover><mi>x</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>⊆</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>⊆</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"></mtd><mtd columnalign="left" style="text-align: left"><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>⊆</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo>∧</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo>⊆</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>⟹</mo><mi>a</mi><mo>=</mo><mi>b</mi></mtd></mtr></mtable></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\bar{a} \; \text{supports}_{min} \; x
\land
\bar{b} \; \text{supports}_{min} \; x
\implies
\bar{a} = \bar{b}
\\ \; \\
\begin{array}{ll}
&amp;
\bar{a} \; \text{supports}_{min} \; x
\land
\bar{b} \; \text{supports}_{min} \; x
\\
= &amp;
(\bar{a}, x) \in
\{ (\bar{a}, x) \; | \; 
\bar{a} \in \mathcal{P}(\mathbb{A}), \;
x \in X, \;
\bar{a} \; \text{supports} \; x, \;
\forall \bar{x}. \; \bar{x} \; \text{supports} \; x \implies
\bar{a} \subseteq \bar{x}
\} \;
\land
\\
&amp;
(\bar{b}, x) \in
\{ (\bar{a}, x) \; | \; 
\bar{a} \in \mathcal{P}(\mathbb{A}), \;
x \in X, \;
\bar{a} \; \text{supports} \; x, \;
\forall \bar{x}. \; \bar{x} \; \text{supports} \; x \implies
\bar{a} \subseteq \bar{x}
\}
\\
= &amp;
\bar{a} \; \text{supports} \; x \; \land \;
(\forall \bar{x}. \; \bar{x} \; \text{supports} \; x \implies
\bar{a} \subseteq \bar{x})
\; \land \;
\\
&amp;
\bar{b} \; \text{supports} \; x
\; \land \;
(\forall \bar{x}. \; \bar{x} \; \text{supports} \; x \implies
\bar{b} \subseteq \bar{x})
\\ \; \\
&amp;
\bar{a} \; \text{supports} \; x
\; \land \;
(\forall \bar{x}. \; \bar{x} \; \text{supports} \; x \implies
\bar{b} \subseteq \bar{x})
\implies
\bar{b} \subseteq \bar{a}
\\
&amp;
\bar{b} \; \text{supports} \; x
\; \land \;
(\forall \bar{x}. \; \bar{x} \; \text{supports} \; x \implies
\bar{a} \subseteq \bar{x})
\implies
\bar{a} \subseteq \bar{b}
\\ \; \\
&amp;
\bar{a} \subseteq \bar{b} \land \bar{b} \subseteq \bar{a} \implies a = b
\end{array}
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-6"><a href="#proof-6">Proof 6</a></h2>
<p>The identity function is supported by the empty set.
<a href="nominal-sets#proof-6-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="postfix">}</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo>∀</mo><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mi>i</mi><mi>d</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>i</mi><mi>d</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mspace width="0.278em"></mspace><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo>∀</mo><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mi>i</mi><mi>d</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mi>π</mi><mo>⋅</mo><mi>i</mi><mi>d</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>π</mi><mo>⋅</mo><msup><mi>π</mi><mn>1</mn></msup><mo>⋅</mo><mi>x</mi><mo>=</mo><mi>x</mi></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\forall \pi. \; (\forall a \in \{\}. \; \pi(a) = a) \implies \forall x. \; \pi \cdot id(\pi^{-1} \cdot x) = id(x)
\\
\iff \; \forall \pi. \; \forall x. \; \pi \cdot id(\pi^{-1} \cdot x) = x
\\ \; \\
\pi \cdot id(\pi^{-1} \cdot x) = \pi \cdot \pi^{1} \cdot x = x
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-7"><a href="#proof-7">Proof 7</a></h2>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext mathvariant="normal">cmp</mtext><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mover><mo>=</mo><mo accent="false">?</mo></mover><mi>b</mi></mrow><annotation encoding="application/x-tex">\text{cmp}(a, b) = a \stackrel{?}{=} b</annotation></semantics></math> is supported by the empty set.
<a href="nominal-sets#proof-7-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="postfix">}</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo>∀</mo><mi>x</mi><mo>,</mo><mi>y</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mtext mathvariant="normal">cmp</mtext><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mtext mathvariant="normal">cmp</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="postfix">}</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo>∀</mo><mi>x</mi><mo>,</mo><mi>y</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mtext mathvariant="normal">cmp</mtext><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo>,</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mtext mathvariant="normal">cmp</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="postfix">}</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo>∀</mo><mi>x</mi><mo>,</mo><mi>y</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mover><mo>=</mo><mo accent="false">?</mo></mover><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mover><mo>=</mo><mo accent="false">?</mo></mover><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="postfix">}</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo>∀</mo><mi>x</mi><mo>,</mo><mi>y</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mover><mo>=</mo><mo accent="false">?</mo></mover><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mover><mo>=</mo><mo accent="false">?</mo></mover><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">booleans contain no names</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo>∀</mo><mi>x</mi><mo>,</mo><mi>y</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mover><mo>=</mo><mo accent="false">?</mo></mover><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mover><mo>=</mo><mo accent="false">?</mo></mover><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">case </mtext><mspace width="0.333em"></mspace></mrow><mi>x</mi><mo>=</mo><mi>y</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⇔</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mover><mo>=</mo><mo accent="false">?</mo></mover><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mtext mathvariant="normal">true</mtext></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mover><mo>=</mo><mo accent="false">?</mo></mover><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mover><mo>=</mo><mo accent="false">?</mo></mover><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>=</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mtext mathvariant="normal">true</mtext></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">case </mtext><mspace width="0.333em"></mspace></mrow><mi>x</mi><mo>≠</mo><mi>y</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⇔</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mover><mo>=</mo><mo accent="false">?</mo></mover><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mtext mathvariant="normal">false</mtext></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mover><mo>=</mo><mo accent="false">?</mo></mover><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><msup><mi>x</mi><mo>′</mo></msup><mover><mo>=</mo><mo accent="false">?</mo></mover><msup><mi>y</mi><mo>′</mo></msup><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> where </mtext><mspace width="0.333em"></mspace></mrow><msup><mi>x</mi><mo>′</mo></msup><mo>≠</mo><msup><mi>y</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mtext mathvariant="normal">injectivity of </mtext><mspace width="0.333em"></mspace></mrow><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mtext mathvariant="normal">false</mtext></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\forall \pi. \; (\forall a \in \{\}. \; \pi(a) = a) \implies \forall x, y. \; \pi \cdot \text{cmp}(\pi^{-1}
\cdot (x, y)) = \text{cmp}(x, y)
\\
\iff \forall \pi. \; (\forall a \in \{\}. \; \pi(a) = a) \implies \forall x, y. \; \pi \cdot \text{cmp}(\pi^{-1}
\cdot x, \pi^{-1} \cdot y) = \text{cmp}(x, y)
\\
\iff \forall \pi. \; (\forall a \in \{\}. \; \pi(a) = a) \implies \forall x, y. \; \pi \cdot ((\pi^{-1}
\cdot x) \stackrel{?}{=} (\pi^{-1} \cdot y)) = (x \stackrel{?}{=} y)
\\
\iff \forall \pi. \; (\forall a \in \{\}. \; \pi(a) = a) \implies \forall x, y. \; ((\pi^{-1}
\cdot x) \stackrel{?}{=} (\pi^{-1} \cdot y)) = (x \stackrel{?}{=} y) \;\;\;\; (\text{booleans contain no names})
\\
\iff \forall \pi. \; \forall x, y. \; ((\pi^{-1}
\cdot x) \stackrel{?}{=} (\pi^{-1} \cdot y)) = (x \stackrel{?}{=} y)
\\ \; \\
\text{case } x = y
\\
\; \; \; \; \iff ((\pi^{-1} \cdot x) \stackrel{?}{=} (\pi^{-1} \cdot y)) = \text{true}
\\
\; \; \; \; (\pi^{-1} \cdot x) \stackrel{?}{=} (\pi^{-1} \cdot y)
\\
\; \; \; \; = (\pi^{-1} \cdot x) \stackrel{?}{=} (\pi^{-1} \cdot x) \; (x = y)
\\
\; \; \; \; = \text{true}
\\ \; \\
\text{case } x \neq y
\\
\; \; \; \; \iff ((\pi^{-1} \cdot x) \stackrel{?}{=} (\pi^{-1} \cdot y)) = \text{false}
\\
\; \; \; \; (\pi^{-1} \cdot x) \stackrel{?}{=} (\pi^{-1} \cdot y)
\\
\; \; \; \; = x&#39; \stackrel{?}{=} y&#39; \text{ where } x&#39; \neq y&#39; \;\;\;\; (\text{injectivity of } \pi^{-1})
\\
\; \; \; \; = \text{false}
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-8"><a href="#proof-8">Proof 8</a></h2>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>a</mi><annotation encoding="application/x-tex">a</annotation></semantics></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>b</mi><annotation encoding="application/x-tex">b</annotation></semantics></math> must be in the support of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext mathvariant="normal">iffy</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mrow><mtext mathvariant="normal">if </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><mover><mo>=</mo><mo accent="false">?</mo></mover><mi>x</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> then </mtext><mspace width="0.333em"></mspace></mrow><mi>b</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> else </mtext><mspace width="0.333em"></mspace></mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">\text{iffy}(x) = \text{if } a \stackrel{?}{=} x \text{ then } b
\text{ else } x</annotation></semantics></math>.
<a href="nominal-sets#proof-8-link">↩︎</a></p>
<h3 id="when-a-is-missing"><a href="#when-a-is-missing">When <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>a</mi><annotation encoding="application/x-tex">a</annotation></semantics></math> is missing</a></h3>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mo stretchy="false" form="prefix">{</mo><mi>b</mi><mo stretchy="false" form="postfix">}</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo>∀</mo><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mtext mathvariant="normal">iffy</mtext><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mtext mathvariant="normal">iffy</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>b</mi><mo>⟹</mo><mo>∀</mo><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mtext mathvariant="normal">iffy</mtext><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mtext mathvariant="normal">iffy</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">can’t prove for all </mtext><mspace width="0.333em"></mspace></mrow><mi>π</mi><mo>,</mo><mi>x</mi><mrow><mtext mathvariant="normal">. counterexample: </mtext><mspace width="0.333em"></mspace></mrow><mi>π</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>,</mo><mspace width="0.278em"></mspace><mi>x</mi><mo>=</mo><mi>a</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtable><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mtext mathvariant="normal">iffy</mtext><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mtext mathvariant="normal">iffy</mtext><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>n</mi><mo>=</mo><mi>a</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">iffy</mtext><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>b</mi></mtd></mtr></mtable></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\forall \pi. \; (\forall a \in \{ b \}. \; \pi(a) = a) \implies \forall x. \; \pi \cdot \text{iffy}(\pi^{-1}
\cdot x) = \text{iffy}(x)
\\
= \forall \pi. \; \pi(b) = b \implies \forall x. \; \pi \cdot \text{iffy}(\pi^{-1}
\cdot x) = \text{iffy}(x)
\\ \; \\
\text{can&#39;t prove for all } \pi, x \text{. counterexample: } \pi = (a \;
n), \; x = a
\\
\begin{array}{ll}
(a \; n) \cdot \text{iffy}((a \; n) \cdot a) &amp; = (a \; n) \cdot \text{iffy}(n) = (a \; n) \cdot n = a
\\
\text{iffy}(a) &amp; = b
\end{array}
\end{array}
</annotation></semantics></math></p>
<h3 id="when-b-is-missing"><a href="#when-b-is-missing">When <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>b</mi><annotation encoding="application/x-tex">b</annotation></semantics></math> is missing</a></h3>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>x</mi><mo>∈</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo>∀</mo><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mtext mathvariant="normal">iffy</mtext><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mtext mathvariant="normal">iffy</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo>⟹</mo><mo>∀</mo><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mtext mathvariant="normal">iffy</mtext><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mtext mathvariant="normal">iffy</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">can’t prove for all </mtext><mspace width="0.333em"></mspace></mrow><mi>π</mi><mo>,</mo><mi>x</mi><mrow><mtext mathvariant="normal">. counterexample: </mtext><mspace width="0.333em"></mspace></mrow><mi>π</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mspace width="0.278em"></mspace><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>,</mo><mspace width="0.278em"></mspace><mi>x</mi><mo>=</mo><mi>a</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtable><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mspace width="0.278em"></mspace><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mtext mathvariant="normal">iffy</mtext><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mspace width="0.278em"></mspace><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mspace width="0.278em"></mspace><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mtext mathvariant="normal">iffy</mtext><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mspace width="0.278em"></mspace><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>b</mi><mo>=</mo><mi>n</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">iffy</mtext><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>b</mi></mtd></mtr></mtable></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\forall \pi. \; (\forall x \in \{ a \}. \; \pi(x) = x) \implies \forall x. \; \pi \cdot \text{iffy}(\pi^{-1}
\cdot x) = \text{iffy}(x)
\\
= \forall \pi. \; \pi(a) = a \implies \forall x. \; \pi \cdot \text{iffy}(\pi^{-1}
\cdot x) = \text{iffy}(x)
\\ \; \\
\text{can&#39;t prove for all } \pi, x \text{. counterexample: } \pi = (b \;
n), \; x = a
\\
\begin{array}{ll}
(b \; n) \cdot \text{iffy}((b \; n) \cdot a) &amp; = (b \; n) \cdot \text{iffy}(a) = (b \; n) \cdot b = n
\\
\text{iffy}(a) &amp; = b
\end{array}
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-9"><a href="#proof-9">Proof 9</a></h2>
<p>Swapping fresh names does nothing.
<a href="nominal-sets#proof-9-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mo>∧</mo><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mo>∧</mo><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mi>a</mi><mo>∉</mo><msub><mtext mathvariant="normal">support</mtext><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>∧</mo><mi>b</mi><mo>∉</mo><msub><mtext mathvariant="normal">support</mtext><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mi>a</mi><mo>∉</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mo>∧</mo><mi>b</mi><mo>∉</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> for some </mtext><mspace width="0.333em"></mspace></mrow><mover><mi>x</mi><mo accent="true">‾</mo></mover><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> where </mtext><mspace width="0.333em"></mspace></mrow><mover><mi>x</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo>∧</mo><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mover><mi>y</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mover><mi>y</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mo>⊆</mo><mover><mi>y</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mover><mi>x</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>=</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mi>π</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>c</mi><mo>∈</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>c</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>c</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>∉</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mo>∧</mo><mi>b</mi><mo>∉</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mo>⟹</mo><mo>∀</mo><mi>c</mi><mo>∈</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mi>a</mi><mo>≠</mo><mi>c</mi><mo>∧</mo><mi>b</mi><mo>≠</mo><mi>c</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>∴</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mi>x</mi></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
a \; \# \; x \land b \; \# \; x \implies (a \; b) \cdot x = x
\\ \; \\
a \; \# \; x \land b \; \# \; x
\\
\iff a \notin \text{support}_{min}(x) \land b \notin \text{support}_{min}(x)
\\
\iff a \notin \bar{x} \land b \notin \bar{x} \text{ for some } \bar{x} \text{ where } \bar{x} \; \text{supports} \; x \land (\forall \bar{y}. \; \bar{y} \; \text{supports} \; x \implies \bar{x} \subseteq \bar{y})
\\ \; \\
\bar{x} \; \text{supports} \; x
\\
\iff \forall \pi. \; (\forall a \in \bar{x}. \; \pi(a) = a) \implies \pi \cdot x = x
\\ \; \\
\pi = (a \; b)
\\
\forall c \in \bar{x}. \; (a \; b)(c) = c \; (a \notin \bar{x} \land b \notin \bar{x} \implies \forall c \in \bar{x}. \; a \neq c \land b \neq c)
\\
\therefore \; (a \; b) \cdot x = x
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-10"><a href="#proof-10">Proof 10</a></h2>
<p>Freshness “distributes” across functions.
<a href="nominal-sets#proof-10-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>f</mi><mo>∧</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>f</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mi>a</mi><mo>∉</mo><msub><mtext mathvariant="normal">support</mtext><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mi>a</mi><mo>∉</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> for some </mtext><mspace width="0.333em"></mspace></mrow><mover><mi>a</mi><mo accent="true">‾</mo></mover><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> where </mtext><mspace width="0.333em"></mspace></mrow><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>f</mi><mo>∧</mo><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mover><mi>b</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>f</mi><mo>⟹</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>⊆</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>f</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo>=</mo><mi>f</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mi>a</mi><mo>∉</mo><msub><mtext mathvariant="normal">support</mtext><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mi>a</mi><mo>∉</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> for some </mtext><mspace width="0.333em"></mspace></mrow><mover><mi>b</mi><mo accent="true">‾</mo></mover><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> where </mtext><mspace width="0.333em"></mspace></mrow><mover><mi>b</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo>∧</mo><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo>⊆</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>=</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>∪</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mo stretchy="false" form="prefix">(</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>∪</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mo stretchy="false" form="prefix">(</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>∪</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mrow><mtext mathvariant="normal">, </mtext><mspace width="0.333em"></mspace></mrow><mover><mi>a</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mo stretchy="false" form="prefix">(</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>∪</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mrow><mtext mathvariant="normal">, </mtext><mspace width="0.333em"></mspace></mrow><mover><mi>b</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mi>a</mi><mo>∉</mo><mo stretchy="false" form="prefix">(</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>∪</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>∉</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>∧</mo><mi>a</mi><mo>∉</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">given </mtext><mspace width="0.333em"></mspace></mrow><mover><mi>c</mi><mo accent="true">‾</mo></mover><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> where </mtext><mspace width="0.333em"></mspace></mrow><mover><mi>c</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>∧</mo><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mover><mi>b</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mover><mi>c</mi><mo accent="true">‾</mo></mover><mo>⊆</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>∪</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>∧</mo><mi>a</mi><mo>∉</mo><mo stretchy="false" form="prefix">(</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>∪</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⟹</mo><mover><mi>c</mi><mo accent="true">‾</mo></mover><mo>⊆</mo><mo stretchy="false" form="prefix">(</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>∪</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo><mo>∧</mo><mi>a</mi><mo>∉</mo><mo stretchy="false" form="prefix">(</mo><mover><mi>a</mi><mo accent="true">‾</mo></mover><mo>∪</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mover><mi>c</mi><mo accent="true">‾</mo></mover><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> minimal</mtext></mrow><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⟹</mo><mi>a</mi><mo>∉</mo><mover><mi>c</mi><mo accent="true">‾</mo></mover></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
a \; \# \; f \land a \; \# \; x \implies a \; \# \; f(x)
\\ \; \\
a \; \# \; f
\\
\iff a \notin \text{support}_{min}(f)
\\
\iff a \notin \bar{a}
\text{ for some } \bar{a} \text{ where } \bar{a} \; \text{supports} \; f \land (\forall \bar{b}. \; \bar{b} \; \text{supports} \; f \implies \bar{a} \subseteq \bar{b})
\\ \; \\
\bar{a} \; \text{supports} \; f
\\
\iff \forall \pi. \; (\forall a \in \bar{a}. \; \pi(a) = a) \implies \pi \cdot f = f
\\ \; \\
a \; \# \; x
\\
\iff a \notin \text{support}_{min}(x)
\\
\iff a \notin \bar{b}
\text{ for some } \bar{b} \text{ where } \bar{b} \; \text{supports} \; x \land (\forall \bar{a}. \; \bar{a} \; \text{supports} \; x \implies \bar{b} \subseteq \bar{a})
\\ \; \\
\bar{a} \; \text{supports} \; x
\\
\iff \forall \pi. \; (\forall a \in \bar{b}. \; \pi(a) = a) \implies \pi \cdot x = x
\\ \; \\
(\bar{a} \cup \bar{b}) \; \text{supports} \; f(x)
\\
\iff \forall \pi. \; (\forall a \in (\bar{a} \cup \bar{b}). \; \pi(a) = a) \implies \pi \cdot f(x) = f(x)
\\
\pi \cdot f(x)
\\
= (\pi \cdot f)(\pi \cdot x)
\\
= f(\pi \cdot x) \; ((\forall a \in (\bar{a} \cup \bar{b}). \; \pi(a) = a) \implies (\forall a \in \bar{a}. \; \pi(a) = a) \text{, } \bar{a} \; \text{supports} \; f)
\\
= f(x) \; ((\forall a \in (\bar{a} \cup \bar{b}). \; \pi(a) = a) \implies (\forall a \in \bar{b}. \; \pi(a) = a) \text{, } \bar{b} \; \text{supports} \; x)
\\ \; \\
a \notin (\bar{a} \cup \bar{b}) \; (a \notin \bar{a} \land a \notin \bar{b})
\\ \; \\
\text{given } \bar{c} \text{ where } \bar{c} \; \text{supports} \; f(x) \land (\forall \bar{b}. \; \bar{b} \; \text{supports} \; f(x) \implies \bar{c} \subseteq \bar{b})
\\
(\bar{a} \cup \bar{b}) \; \text{supports} \; f(x) \land a \notin (\bar{a} \cup \bar{b})
\\
\implies \bar{c} \subseteq (\bar{a} \cup \bar{b}) \land a \notin (\bar{a} \cup \bar{b}) \; (\bar{c} \text{ minimal})
\\
\implies a \notin \bar{c}
\\
\iff a \; \# \; f(x)
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-11"><a href="#proof-11">Proof 11</a></h2>
<p>The support of name binding: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo></mrow><annotation encoding="application/x-tex">\text{support}(\langle a \rangle x) = \text{support}(x) - \{ a \}</annotation></semantics></math>.
<a href="nominal-sets#proof-11-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><msub><mtext mathvariant="normal">supports</mtext><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>∧</mo><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mover><mi>b</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mo stretchy="false" form="postfix">)</mo><mo>⊆</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
(\text{support}(x) - \{ a \}) \; \text{supports}_{min} \; \langle a \rangle x
\\
\iff ((\text{support}(x) - \{ a \}) \; \text{supports} \; \langle a \rangle x) \land (\forall \bar{b}. \; \bar{b} \; \text{supports} \; \langle a \rangle x \implies (\text{support}(x) - \{ a \}) \subseteq \bar{b})
\end{array}
</annotation></semantics></math></p>
<h3 id="support"><a href="#support">Support</a></h3>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>b</mi><mo>∈</mo><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mi>π</mi><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mi>π</mi><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">⟩</mo><mi>π</mi><mo>⋅</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>∀</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mi>x</mi><mo>,</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>,</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>π</mi><mo>⋅</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mrow><mtext mathvariant="normal">case </mtext><mspace width="0.333em"></mspace></mrow><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>π</mi><mo>⋅</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo>∧</mo><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>b</mi><mo>∈</mo><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo>∀</mo><mi>b</mi><mo>∈</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mrow><mtext mathvariant="normal">case </mtext><mspace width="0.333em"></mspace></mrow><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi>a</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mi>π</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>b</mi><mn>1</mn></msub><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>b</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mi>.</mi><mi>.</mi><mi>.</mi><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>b</mi><mi>n</mi></msub><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>b</mi><mi>n</mi></msub><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">A.1</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> for all </mtext><mspace width="0.333em"></mspace></mrow><msub><mi>b</mi><mi>i</mi></msub><mo>∈</mo><mi>𝔸</mi><mo>−</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> where </mtext><mspace width="0.333em"></mspace></mrow><mi>π</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>b</mi><mi>i</mi></msub><mo stretchy="false" form="postfix">)</mo><mo>∉</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>∧</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>b</mi><mi>i</mi></msub><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>b</mi><mi>j</mi></msub><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><msub><mi>b</mi><mi>j</mi></msub><mo>≠</mo><msub><mi>b</mi><mi>i</mi></msub><mo>≠</mo><mi>a</mi><mo>≠</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><msub><mi>b</mi><mi>i</mi></msub><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mo>∧</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>b</mi><mi>i</mi></msub><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mtext mathvariant="normal">A.9</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">A.21</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mrow><mtext mathvariant="normal">assume </mtext><mspace width="0.333em"></mspace></mrow><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>∈</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⟹</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi>a</mi><mo>⟹</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>∈</mo><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∧</mo><mo>∀</mo><mi>b</mi><mo>∈</mo><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⟹</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> — contradiction</mtext></mrow></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>∴</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mo>∧</mo><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mi>x</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> — A.9</mtext></mrow><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
(\text{support}(x) - \{ a \}) \; \text{supports} \; \langle a \rangle x
\\
\iff \forall \pi. \; (\forall b \in (\text{support}(x) - \{ a \}). \; \pi(b) = b) \implies \pi \cdot (\langle a \rangle x) = \langle a \rangle x
\\ \; \\
\pi \cdot (\langle a \rangle x)
\\
= \langle \pi(a) \rangle \pi \cdot x
\\
\; \; \; \; \forall b. \; b \; \# \; (a, x, \pi(a), \pi \cdot x) \implies (a \; b) \cdot x = (\pi(a) \; b) \cdot (\pi \cdot x)
\\
\; \; \; \; (\pi(a) \; b) \cdot \pi \cdot x
\\
\; \; \; \; \text{case } \pi(a) = a
\\
\; \; \; \; \; \; \; \; = (a \; b) \cdot \pi \cdot x
\\
\; \; \; \; \; \; \; \; = (a \; b) \cdot x \; (\pi(a) = a \land (\forall b \in (\text{support}(x) - \{a\}). \; \pi(b) = b) \implies \forall b \in \text{support}(x). \; \pi(b) = b)
\\
\; \; \; \; \text{case } \pi(a) \neq a
\\
\; \; \; \; \; \; \; \; \; \; \; \; \pi = (a \; \pi(a)) \circ (b_1 \; \pi(b_1)) \circ ... \circ (b_n \; \pi(b_n)) \; (\text{A.1})
\\
\; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \; \text{ for all } b_i \in \mathbb{A} - \text{support}(x) - \{a\} \text{ where } \pi(b_i) \notin \text{support}(x) \land \pi(b_i) \neq \pi(b_j) \neq b_j \neq b_i \neq a \neq \pi(a)
\\
\; \; \; \; \; \; \; \; = (\pi(a) \; b) \cdot (a \; \pi(a)) \cdot x \; (b_i \; \# \; x \land \pi(b_i) \; \# \; x \text{A.9})
\\
\; \; \; \; \; \; \; \; = ((\pi(a) \; b) \circ (a \; \pi(a))) \cdot x
\\
\; \; \; \; \; \; \; \; = ((a \; b) \circ (\pi(a) \; b)) \cdot x \; (\text{A.21})
\\
\; \; \; \; \; \; \; \; = (a \; b) \cdot (\pi(a) \; b) \cdot x
\\
\; \; \; \; \; \; \; \; \; \; \; \; \text{assume } \pi(a) \in \text{support}(x)
\\
\; \; \; \; \; \; \; \; \; \; \; \; \implies \pi(\pi(a)) = \pi(a) \; ((\pi(a) \neq a \implies \pi(a) \in (\text{support}(x) - \{a\})) \land \forall b \in (\text{support}(x) - \{a\}). \; \pi(b) = b)
\\
\; \; \; \; \; \; \; \; \; \; \; \; \implies \pi(a) = a \text{ --- contradiction}
\\
\; \; \; \; \; \; \; \; \; \; \; \; \therefore \pi(a) \; \# \; x
\\
\; \; \; \; \; \; \; \; = (a \; b) \cdot x \; (\pi(a) \; \# \; x \land b \; \# \; x \implies (\pi(a) \; b) \cdot x = x \text{ --- A.9})
\\
= \langle a \rangle x
\end{array}
</annotation></semantics></math></p>
<h3 id="minimality"><a href="#minimality">Minimality</a></h3>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mover><mi>b</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo>⟹</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mo>⊆</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mover><mi>b</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo>⟹</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo>∪</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">assume </mtext><mspace width="0.333em"></mspace></mrow><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>b</mi><mo>∈</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mi>π</mi><mo>⋅</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⇔</mo><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>b</mi><mo>∈</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo stretchy="false" form="prefix">⟨</mo><mi>π</mi><mo>⋅</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">assume </mtext><mspace width="0.333em"></mspace></mrow><mo>∀</mo><mi>b</mi><mo>∈</mo><mo stretchy="false" form="prefix">(</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo>∪</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>b</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⇔</mo><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>b</mi><mo>∈</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>∧</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">⟨</mo><mi>π</mi><mo>⋅</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">via assumptions 1 and 2</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo>∃</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>=</mo><mi>x</mi><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">swapping involutive</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mover><mi>b</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⟹</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo>∪</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⟹</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>⊆</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover><mo>∪</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> minimal</mtext></mrow><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⟹</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo><mo>⊆</mo><mover><mi>b</mi><mo accent="true">‾</mo></mover></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\forall \bar{b}. \; \bar{b} \; \text{supports} \; \langle a \rangle x \implies \text{support}(x) - \{a\} \subseteq \bar{b}
\\ \; \\
\bar{b} \; \text{supports} \; \langle a \rangle x \implies \bar{b} \cup \{a\} \; \text{supports} \; x
\\
\text{assume } \forall \pi. \; (\forall b \in \bar{b}. \; \pi(b) = b) \implies \pi \cdot \langle a \rangle x = \langle a \rangle x
\\
\; \; \; \; \; \; \iff \forall \pi. \; (\forall b \in \bar{b}. \; \pi(b) = b) \implies \langle \pi \cdot a \rangle \pi \cdot x = \langle a \rangle x
\\
\text{assume } \forall b \in (\bar{b} \cup \{a\}). \; \pi(b) = b
\\
\; \; \; \; \; \; \iff (\forall b \in \bar{b}. \; \pi(b) = b) \land \pi(a) = a
\\
\langle \pi \cdot a \rangle \pi \cdot x = \langle a \rangle x \; \; (\text{via assumptions 1 and 2})
\\
\iff \langle a \rangle \pi \cdot x = \langle a \rangle x \; \; (\pi(a) = a)
\\
\iff \exists b. \; (a \; b) \cdot \pi \cdot x = (a \; b) \cdot x
\\
\iff (a \; b) \cdot (a \; b) \cdot \pi \cdot x = (a \; b) \cdot (a \; b) \cdot x
\\
\iff \pi \cdot x = x \; \; (\text{swapping involutive})
\\ \; \\
\bar{b} \; \text{supports} \; \langle a \rangle x
\\
\implies \bar{b} \cup \{a\} \; \text{supports} \; x
\\
\implies \text{support}(x) \subseteq \bar{b} \cup \{a\} \; (\text{support}(x) \text{ minimal})
\\
\implies \text{support}(x) - \{a\} \subseteq \bar{b}
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-12"><a href="#proof-12">Proof 12</a></h2>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>b</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo>⇔</mo><mi>a</mi><mo>=</mo><mi>b</mi><mo>∨</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi></mrow><annotation encoding="application/x-tex">a \; \# \; \langle b \rangle x \iff a = b \lor a \; \# \; x</annotation></semantics></math>   <a href="nominal-sets#proof-12-link">↩︎</a></p>
<h3 id="forward"><a href="#forward">Forward</a></h3>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">assume </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>b</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">case </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><mo>=</mo><mi>b</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mi>a</mi><mo>=</mo><mi>b</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">case </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><mo>≠</mo><mi>b</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>b</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⇔</mo><mi>a</mi><mo>∉</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>b</mi><mo stretchy="false" form="postfix">}</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⟹</mo><mi>a</mi><mo>∉</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⇔</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{assume } a \; \# \; \langle b \rangle x
\\
\text{case } a = b
\\
\; \; \; \; a = b
\\
\text{case } a \neq b
\\
\; \; \; \; a \; \# \; \langle b \rangle x
\\
\; \; \; \; \iff a \notin \text{support}(x) - \{b\}
\\
\; \; \; \; \implies a \notin \text{support}(x)
\\
\; \; \; \; \iff a \; \# \; x
\end{array}
</annotation></semantics></math></p>
<h3 id="backward"><a href="#backward">Backward</a></h3>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">assume </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><mo>=</mo><mi>b</mi><mo>∨</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">case </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><mo>=</mo><mi>b</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><mi>b</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>b</mi><mo stretchy="false" form="postfix">}</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mi>a</mi><mo>∉</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>a</mi><mo stretchy="false" form="postfix">}</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⇔</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>b</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">case </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><mi>b</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>b</mi><mo stretchy="false" form="postfix">}</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⇔</mo><mi>a</mi><mo>∉</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⟹</mo><mi>a</mi><mo>∉</mo><mtext mathvariant="normal">support</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">{</mo><mi>b</mi><mo stretchy="false" form="postfix">}</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⇔</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>b</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{assume } a = b \lor a \; \# \; x
\\
\text{case } a = b
\\
\; \; \; \; \text{support}(\langle b \rangle x)
\\
\; \; \; \; = \text{support}(x) - \{b\}
\\
\; \; \; \; = \text{support}(x) - \{a\}
\\
\; \; \; \; a \notin \text{support}(x) - \{a\}
\\
\; \; \; \; \iff a \; \# \; \langle b \rangle x
\\
\text{case } a \; \# \; x
\\
\; \; \; \; \text{support}(\langle b \rangle x)
\\
\; \; \; \; = \text{support}(x) - \{b\}
\\
\; \; \; \; a \; \# \; x
\\
\; \; \; \; \iff a \notin \text{support}(x)
\\
\; \; \; \; \implies a \notin \text{support}(x) - \{b\}
\\
\; \; \; \; \iff a \; \# \; \langle b \rangle x
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-13"><a href="#proof-13">Proof 13</a></h2>
<p>The interchangeability of “some fresh” and “any fresh”. <a href="nominal-sets#proof-13-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="center" style="text-align: center"><mo>∃</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mi>x</mi><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo>,</mo><msup><mi>x</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>∧</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="center" style="text-align: center"><mo>⇔</mo></mtd></mtr><mtr><mtd columnalign="center" style="text-align: center"><mo>∀</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mi>x</mi><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo>,</mo><msup><mi>x</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{c}
\exists b. \; b \; \# \; (a, x, a&#39;, x&#39;) \land (a \; b) \cdot x = (a&#39; \; b) \cdot x&#39;
\\
\iff
\\
\forall b. \; b \; \# \; (a, x, a&#39;, x&#39;) \implies (a \; b) \cdot x = (a&#39; \; b) \cdot x&#39;
\end{array}
</annotation></semantics></math></p>
<h3 id="forward-1"><a href="#forward-1">Forward</a></h3>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">assume </mtext><mspace width="0.333em"></mspace></mrow><mo>∃</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mi>x</mi><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo>,</mo><msup><mi>x</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>∧</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">assume </mtext><mspace width="0.333em"></mspace></mrow><mo>∀</mo><msup><mi>b</mi><mo>′</mo></msup><mi>.</mi><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mi>x</mi><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><msup><mi>x</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">A.21</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><msup><mi>x</mi><mo>′</mo></msup><mo>∧</mo><msup><mi>b</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><msup><mi>x</mi><mo>′</mo></msup><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> — A.9</mtext></mrow><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{assume } \exists b. \; b \; \# \; (a, x, a&#39;, x&#39;) \land (a \; b) \cdot x = (a&#39; \; b) \cdot x&#39;
\\
\text{assume } \forall b&#39;. \; b&#39; \; \# \; (a, x, a&#39; x&#39;)
\\
(a \; b) \cdot x = (a&#39; \; b) \cdot x&#39;
\\
\iff (b \; b&#39;) \cdot (a \; b) \cdot x = (b \; b&#39;) \cdot (a&#39; \; b) \cdot x&#39;
\\
\iff ((b \; b&#39;) \circ (a \; b)) \cdot x = ((b \; b&#39;) \circ (a&#39; \; b)) \cdot x&#39;
\\
\iff ((a \; b&#39;) \circ (b \; b&#39;)) \cdot x = ((a&#39; \; b&#39;) \circ (b \; b&#39;)) \cdot x&#39; \; (\text{A.21})
\\
\iff (a \; b&#39;) \cdot (b \; b&#39;) \cdot x = (a&#39; \; b&#39;) \cdot (b \; b&#39;) \cdot x&#39;
\\
\iff (a \; b&#39;) \cdot x = (a&#39; \; b&#39;) \cdot x&#39; \; (b \; \# \; x&#39; \land b&#39; \; \# \; x&#39; \text{ --- A.9})
\end{array}
</annotation></semantics></math></p>
<h3 id="backward-1"><a href="#backward-1">Backward</a></h3>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">assume </mtext><mspace width="0.333em"></mspace></mrow><mo>∀</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mi>x</mi><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo>,</mo><msup><mi>x</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>∃</mo><msup><mi>b</mi><mo>′</mo></msup><mi>.</mi><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mi>x</mi><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo>,</mo><msup><mi>x</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">&quot;choose-a-fresh-name&quot;</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mi>∧</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><msup><mi>b</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">original assumption</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{assume } \forall b. \; b \; \# \; (a, x, a&#39;, x&#39;) \implies (a \; b) \cdot x = (a&#39; \; b) \cdot x&#39;
\\
\exists b&#39;. \; b&#39; \; \# \; (a, x, a&#39;, x&#39;) \; (\text{&quot;choose-a-fresh-name&quot;})
\\
\land
\\
(a \; b&#39;) \cdot x = (a&#39; \; b&#39;) \cdot x&#39; \; (\text{original assumption})
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-14"><a href="#proof-14">Proof 14</a></h2>
<p>Equivariant functions are supported by the empty set.
<a href="nominal-sets#proof-14-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>π</mi><mo>,</mo><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><msub><mtext mathvariant="normal">supports</mtext><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub><mspace width="0.278em"></mspace><mi>f</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><msub><mtext mathvariant="normal">supports</mtext><mrow><mi>m</mi><mi>i</mi><mi>n</mi></mrow></msub><mspace width="0.278em"></mspace><mi>f</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>f</mi><mo>∧</mo><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mover><mi>x</mi><mo accent="true">‾</mo></mover><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="postfix">}</mo><mo>⊆</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>f</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="postfix">}</mo><mo>⊆</mo><mover><mi>x</mi><mo accent="true">‾</mo></mover><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> trivial</mtext></mrow><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="postfix">}</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">supports</mtext><mspace width="0.278em"></mspace><mi>f</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo>∀</mo><mi>π</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo>∀</mo><mi>a</mi><mo>∈</mo><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="postfix">}</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo>=</mo><mi>f</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>π</mi><mo>⋅</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> equivariant</mtext></mrow><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
(\forall \pi, x. \; f (\pi \cdot x) = \pi \cdot f(x)) \implies \{\} \; \text{supports}_{min} \; f
\\ \; \\
\{\} \; \text{supports}_{min} \; f 
\\
\iff \{\} \; \text{supports} \; f \land (\forall \bar{x}. \; \bar{x} \; \text{supports} \; x \implies \{\} \subseteq \bar{x})
\\
\iff \{\} \; \text{supports} \; f \; (\forall \bar{x}. \; \{\} \subseteq \bar{x} \text{ trivial})
\\ \; \\
\{\} \; \text{supports} \; f
\\
\iff \forall \pi. \; (\forall a \in \{\}. \; \pi(a) = a) \implies \pi \cdot f = f
\\
\forall x. \; (\pi \cdot f)(x)
\\
= \pi \cdot f(\pi^{-1} \cdot x)
\\
= \pi \cdot \pi^{-1} f(x) \; (f \text{ equivariant})
\\
= f(x)
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-15"><a href="#proof-15">Proof 15</a></h2>
<p>The identity function is equivariant.
<a href="nominal-sets#proof-15-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext mathvariant="normal">id</mtext><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>=</mo><mi>π</mi><mo>⋅</mo><mtext mathvariant="normal">id</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">
\text{id}(\pi \cdot x) = \pi \cdot x = \pi \cdot \text{id}(x)
</annotation></semantics></math></p>
<h2 id="proof-16"><a href="#proof-16">Proof 16</a></h2>
<p>The composition of two equivariant functions is equivariant.
<a href="nominal-sets#proof-16-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"></mtd><mtd columnalign="left" style="text-align: left"><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>g</mi><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo></mtd><mtd columnalign="left" style="text-align: left"><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>g</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mrow><mtext mathvariant="normal">equivariance of </mtext><mspace width="0.333em"></mspace></mrow><mi>g</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo></mtd><mtd columnalign="left" style="text-align: left"><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>g</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mrow><mtext mathvariant="normal">equivariance of </mtext><mspace width="0.333em"></mspace></mrow><mi>f</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{lll}
&amp; f(g(\pi \cdot x))
\\
= &amp; f(\pi \cdot g(x)) &amp; (\text{equivariance of } g)
\\
= &amp; \pi \cdot f(g(x)) &amp; (\text{equivariance of } f)
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-17"><a href="#proof-17">Proof 17</a></h2>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtext mathvariant="normal">Nom</mtext><annotation encoding="application/x-tex">\text{Nom}</annotation></semantics></math> has a terminal object, which is the singleton set. <a
href="nominal-sets#proof-17-link">↩︎</a></p>
<p>The singleton set <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">{</mo><mi>*</mi><mo stretchy="false" form="postfix">}</mo></mrow><annotation encoding="application/x-tex">\{*\}</annotation></semantics></math> has the trivial permutation action <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi><mo>⋅</mo><mi>*</mi><mo>=</mo><mi>*</mi></mrow><annotation encoding="application/x-tex">\pi \cdot * = *</annotation></semantics></math>.</p>
<p>For every nominal set <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>X</mi><annotation encoding="application/x-tex">X</annotation></semantics></math>, there is a single function <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mn>𝟙</mn><mi>X</mi></msub><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mi>X</mi><mo>→</mo><mo stretchy="false" form="prefix">{</mo><mi>*</mi><mo stretchy="false" form="postfix">}</mo></mrow><annotation encoding="application/x-tex">\mathbb{1}_X \; : \; X \rightarrow \{*\}</annotation></semantics></math>:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><msub><mn>𝟙</mn><mi>X</mi></msub><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mi>X</mi><mo>→</mo><mo stretchy="false" form="prefix">{</mo><mi>*</mi><mo stretchy="false" form="postfix">}</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><msub><mn>𝟙</mn><mi>X</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>*</mi></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\mathbb{1}_X \; : \; X \rightarrow \{*\}
\\
\mathbb{1}_X(x) = *
\end{array}
</annotation></semantics></math></p>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mn>𝟙</mn><mi>X</mi></msub><annotation encoding="application/x-tex">\mathbb{1}_X</annotation></semantics></math> is equivariant:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><msub><mn>𝟙</mn><mi>X</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>*</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>π</mi><mo>⋅</mo><mi>*</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>π</mi><mo>⋅</mo><msub><mn>𝟙</mn><mi>X</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\mathbb{1}_X(\pi \cdot x)
\\
= *
\\
= \pi \cdot *
\\
= \pi \cdot \mathbb{1}_X(x)
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-18"><a href="#proof-18">Proof 18</a></h2>
<p>Introduction and elimination of pairs is equivariant.
<a href="nominal-sets#proof-18-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">fst</mtext><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mi>X</mi><mo>×</mo><mi>Y</mi><mo>→</mo><mi>X</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">fst</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">fst</mtext><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mtext mathvariant="normal">fst</mtext><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>,</mo><mi>π</mi><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>=</mo><mi>π</mi><mo>⋅</mo><mtext mathvariant="normal">fst</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">snd</mtext><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mi>X</mi><mo>×</mo><mi>Y</mi><mo>→</mo><mi>Y</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">snd</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>y</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">snd</mtext><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mtext mathvariant="normal">snd</mtext><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>,</mo><mi>π</mi><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>π</mi><mo>⋅</mo><mi>y</mi><mo>=</mo><mi>π</mi><mo>⋅</mo><mtext mathvariant="normal">snd</mtext><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">pair</mtext><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>Z</mi><mo>→</mo><mi>X</mi><mo stretchy="false" form="postfix">)</mo><mo>×</mo><mo stretchy="false" form="prefix">(</mo><mi>Z</mi><mo>→</mo><mi>Y</mi><mo stretchy="false" form="postfix">)</mo><mo>→</mo><mo stretchy="false" form="prefix">(</mo><mi>Z</mi><mo>→</mo><mi>X</mi><mo>×</mo><mi>Y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">pair</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>,</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>λ</mi><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>,</mo><mi>g</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">pair</mtext><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>,</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mtext mathvariant="normal">pair</mtext><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo>,</mo><mi>π</mi><mo>⋅</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>λ</mi><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>,</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>λ</mi><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>,</mo><mi>π</mi><mo>⋅</mo><mi>g</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>λ</mi><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>,</mo><mi>g</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>λ</mi><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mi>y</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo>,</mo><mi>g</mi><mo stretchy="false" form="prefix">(</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>λ</mi><mi>x</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mtext mathvariant="normal">pair</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>,</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>π</mi><mo>⋅</mo><mtext mathvariant="normal">pair</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>,</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{fst} \; : \; X \times Y \rightarrow X
\\
\text{fst}(x, y) = x
\\ \; \\
\text{fst}(\pi \cdot (x, y)) =
\text{fst}(\pi \cdot x, \pi \cdot y) =
\pi \cdot x =
\pi \cdot \text{fst}(x, y)
\\ \; \\
\text{snd} \; : \; X \times Y \rightarrow Y
\\
\text{snd}(x, y) = y
\\ \; \\
\text{snd}(\pi \cdot (x, y)) =
\text{snd}(\pi \cdot x, \pi \cdot y) =
\pi \cdot y =
\pi \cdot \text{snd}(x, y)
\\ \; \\
\text{pair} \; : \; (Z \rightarrow X) \times (Z \rightarrow Y) \rightarrow (Z \rightarrow X \times Y)
\\
\text{pair}(f, g) = \lambda x. \; (f(x), g(x))
\\ \; \\
\text{pair}(\pi \cdot (f, g))
\\
= \text{pair}(\pi \cdot f, \pi \cdot g)
\\
= \lambda x. \; ((\pi \cdot f)(x), (\pi \cdot g)(x))
\\
= \lambda x. \; (\pi \cdot f(\pi^{-1} \cdot x), \pi \cdot g(\pi^{-1} \cdot x))
\\
= \lambda x. \; \pi \cdot (f(\pi^{-1} \cdot x), g(\pi^{-1} \cdot x))
\\
= \lambda x. \; \pi \cdot (\lambda y. \; (f(y), g(y))) (\pi^{-1} \cdot x)
\\
= \lambda x. \; \pi \cdot \text{pair}(f, g) (\pi^{-1} \cdot x)
\\
= \pi \cdot \text{pair}(f, g)
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-19"><a href="#proof-19">Proof 19</a></h2>
<p>Introduction and elimination of coproducts is equivariant.
<a href="nominal-sets#proof-19-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><msub><mtext mathvariant="normal">in</mtext><mi>L</mi></msub><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mi>X</mi><mo>→</mo><mi>X</mi><mo>+</mo><mi>Y</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><msub><mtext mathvariant="normal">in</mtext><mi>L</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">L</mtext><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><msub><mtext mathvariant="normal">in</mtext><mi>L</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">L</mtext><mo>,</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>π</mi><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">L</mtext><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>π</mi><mo>⋅</mo><msub><mtext mathvariant="normal">in</mtext><mi>L</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><msub><mtext mathvariant="normal">in</mtext><mi>R</mi></msub><mo>:</mo><mi>Y</mi><mo>→</mo><mi>X</mi><mo>+</mo><mi>Y</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><msub><mtext mathvariant="normal">in</mtext><mi>R</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">R</mtext><mo>,</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><msub><mtext mathvariant="normal">in</mtext><mi>R</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">R</mtext><mo>,</mo><mi>π</mi><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>π</mi><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">R</mtext><mo>,</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>π</mi><mo>⋅</mo><msub><mtext mathvariant="normal">in</mtext><mi>R</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">match</mtext><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>X</mi><mo>→</mo><mi>Z</mi><mo stretchy="false" form="postfix">)</mo><mo>×</mo><mo stretchy="false" form="prefix">(</mo><mi>Y</mi><mo>→</mo><mi>Z</mi><mo stretchy="false" form="postfix">)</mo><mo>→</mo><mi>X</mi><mo>+</mo><mi>Y</mi><mo>→</mo><mi>Z</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">match</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>,</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">L</mtext><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">R</mtext><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>g</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">match</mtext><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>,</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mtext mathvariant="normal">match</mtext><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo>,</mo><mi>π</mi><mo>⋅</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">L</mtext><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">R</mtext><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">L</mtext><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">R</mtext><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mi>g</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>λ</mi><mi>y</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">L</mtext><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">R</mtext><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mi>g</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>λ</mi><mi>y</mi><mi>.</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">L</mtext><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">R</mtext><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mi>g</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>λ</mi><mi>y</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">L</mtext><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">R</mtext><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mi>g</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>λ</mi><mi>y</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>π</mi><mo>⋅</mo><mtext mathvariant="normal">match</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>,</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>π</mi><mo>⋅</mo><mtext mathvariant="normal">match</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>,</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{in}_L \; : \; X \rightarrow X + Y
\\
\text{in}_L(x) = (\text{L}, x)
\\ \; \\
\text{in}_L(\pi \cdot x) = (\text{L}, \pi \cdot x) = \pi \cdot (\text{L}, x) = \pi \cdot \text{in}_L(x)
\\ \; \\
\text{in}_R : Y \rightarrow X + Y
\\
\text{in}_R(y) = (\text{R}, y)
\\ \; \\
\text{in}_R(\pi \cdot y) = (\text{R}, \pi \cdot y) = \pi \cdot (\text{R}, y) = \pi \cdot \text{in}_R(y)
\\ \; \\
\text{match} \; : \; (X \rightarrow Z) \times (Y \rightarrow Z) \rightarrow X + Y \rightarrow Z
\\
\text{match}(f, g) = (\lambda (\text{L}, x). \; f(x)) \; | \; (\lambda (\text{R}, x). \; g(x))
\\ \; \\
\text{match}(\pi \cdot (f, g))
\\
= \text{match}(\pi \cdot f, \pi \cdot g)
\\
= (\lambda (\text{L}, x). \; (\pi \cdot f)(x)) \; | \; (\lambda (\text{R}, x). \; (\pi \cdot g)(x))
\\
= (\lambda (\text{L}, x). \; \pi \cdot f(\pi^{-1} \cdot x)) \; | \; (\lambda (\text{R}, x). \; \pi
\cdot g(\pi^{-1} \cdot x))
\\
= \lambda y. \; ((\lambda (\text{L}, x). \; \pi \cdot f(\pi^{-1} \cdot x)) \; | \; (\lambda (\text{R}, x). \; \pi
\cdot g(\pi^{-1} \cdot x)))(y)
\\
= \lambda y. \; ((\lambda (\text{L}, x). \; \pi \cdot f(x)) \; | \; (\lambda (\text{R}, x). \; \pi
\cdot g(x)))(\pi^{-1} \cdot y)
\\
= \lambda y. \; \pi \cdot ((\lambda (\text{L}, x). \; f(x)) \; | \; (\lambda (\text{R}, x). \; g(x)))(\pi^{-1} \cdot y)
\\
= \lambda y. \; \pi \cdot \text{match}(f,g)(\pi^{-1} \cdot y)
\\
= \pi \cdot \text{match}(f,g)
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-20"><a href="#proof-20">Proof 20</a></h2>
<p>Finitely supported functions between nominal sets are exponential objects in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow><annotation encoding="application/x-tex">Nom</annotation></semantics></math>.
<a href="nominal-sets#proof-20-link">↩︎</a></p>
<p>Firstly, not all functions are finitely supported, which means that in general <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi><mo>→</mo><mi>B</mi></mrow><annotation encoding="application/x-tex">A \rightarrow B</annotation></semantics></math>
(for nominal sets <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>A</mi><annotation encoding="application/x-tex">A</annotation></semantics></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>B</mi><annotation encoding="application/x-tex">B</annotation></semantics></math>) is
not itself a nominal set. The set of finitely supported functions <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi><msub><mo>→</mo><mtext mathvariant="normal">fs</mtext></msub><mi>B</mi></mrow><annotation encoding="application/x-tex">A \rightarrow_{\text{fs}} B</annotation></semantics></math> is a
nominal set.</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><msup><mi>B</mi><mi>A</mi></msup><mo>=</mo><mi>A</mi><msub><mo>→</mo><mtext mathvariant="normal">fs</mtext></msub><mi>B</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">eval</mtext><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><msup><mi>B</mi><mi>A</mi></msup><mo>×</mo><mi>A</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>B</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">eval</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mi>λ</mi><mi>f</mi><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><msup><mi>B</mi><mi>A</mi></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mi>λ</mi><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><msub><msup><mi>f</mi><mo>′</mo></msup><mi>x</mi></msub></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mtext mathvariant="normal">where</mtext></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><msub><msup><mi>f</mi><mo>′</mo></msup><mi>x</mi></msub><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mi>A</mi><msub><mo>→</mo><mtext mathvariant="normal">fs</mtext></msub><mi>B</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><msub><msup><mi>f</mi><mo>′</mo></msup><mi>x</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
B^A = A \rightarrow_{\text{fs}} B
\\ \; \\
\text{eval} \; : \; B^A \times A \rightarrow_{Nom} B
\\
\text{eval}(f, x) = f(x)
\\ \; \\
\lambda f \; : \; X \rightarrow_{Nom} B^A
\\
\lambda f(x) = f&#39;_x
\\ \; \;
\text{where}
\\
\; \; \; \; f&#39;_x \; : \; A \rightarrow_{\text{fs}} B
\\
\; \; \; \; f&#39;_x(a) = f(x, a)
\end{array}
</annotation></semantics></math></p>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtext mathvariant="normal">eval</mtext><annotation encoding="application/x-tex">\text{eval}</annotation></semantics></math> is equivariant:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">eval</mtext><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mtext mathvariant="normal">eval</mtext><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo>,</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>π</mi><mo>⋅</mo><mtext mathvariant="normal">eval</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>,</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{eval}(\pi \cdot (f, x))
\\
= \text{eval}(\pi \cdot f, \pi \cdot x)
\\
= (\pi \cdot f)(\pi \cdot x)
\\
= \pi \cdot f(\pi^{-1} \cdot \pi \cdot x)
\\
= \pi \cdot f(x)
\\
= \pi \cdot \text{eval}(f, x)
\end{array}
</annotation></semantics></math></p>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>λ</mi><mi>f</mi></mrow><annotation encoding="application/x-tex">\lambda f</annotation></semantics></math> is equivariant:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mi>λ</mi><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><msub><msup><mi>f</mi><mo>′</mo></msup><mrow><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow></msub></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>∀</mo><mi>a</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>,</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>⋅</mo><mi>x</mi><mo>,</mo><mi>π</mi><mo>⋅</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mi>π</mi><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><msup><mi>π</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>π</mi><mo>⋅</mo><msub><msup><mi>f</mi><mo>′</mo></msup><mi>x</mi></msub></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>π</mi><mo>⋅</mo><mi>λ</mi><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\lambda f(\pi \cdot x)
\\
= f&#39;_{(\pi \cdot x)}
\\
\; \; \; \; \forall a. \; f(\pi \cdot x, a)
\\
\; \; \; \; = f(\pi \cdot x, \pi \cdot \pi^{-1} \cdot a)
\\
\; \; \; \; = \pi \cdot f(x, \pi^{-1} \cdot a)
\\
= \pi \cdot f&#39;_x
\\
= \pi \cdot \lambda f(x)
\end{array}
</annotation></semantics></math></p>
<p>Universal property:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>∈</mo><mi>X</mi><mo>×</mo><mi>A</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>B</mi><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mo>∃</mo><mi>!</mi><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mi>f</mi><mo>∈</mo><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><msup><mi>B</mi><mi>A</mi></msup><mo stretchy="false" form="postfix">)</mo><mi>.</mi><mspace width="0.278em"></mspace><mtext mathvariant="normal">eval</mtext><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mi>f</mi><mo>×</mo><mtext mathvariant="normal">id</mtext><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>f</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">given </mtext><mspace width="0.333em"></mspace></mrow><mi>f</mi><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mi>X</mi><mo>×</mo><mi>A</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>B</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">eval</mtext><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mi>f</mi><mo>×</mo><mtext mathvariant="normal">id</mtext><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mtext mathvariant="normal">eval</mtext><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mi>f</mi><mo>×</mo><mtext mathvariant="normal">id</mtext><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mtext mathvariant="normal">eval</mtext><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>,</mo><mtext mathvariant="normal">id</mtext><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mtext mathvariant="normal">eval</mtext><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>,</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>λ</mi><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\forall (f \in X \times A \rightarrow_{Nom} B).
\;
\exists ! (\lambda f \in X \rightarrow_{Nom} B^A).
\;
\text{eval} \circ (\lambda f \times \text{id}) = f
\\ \; \\
\text{given } f \; : \; X \times A \rightarrow_{Nom} B
\\ \; \\
(\text{eval} \circ (\lambda f \times \text{id}))(x, a)
\\
= \text{eval}((\lambda f \times \text{id})(x, a))
\\
= \text{eval}(\lambda f(x), \text{id}(a))
\\
= \text{eval}(\lambda f(x), a)
\\
= \lambda f(x)(a)
\\
= f(x, a)
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-21"><a href="#proof-21">Proof 21</a></h2>
<p>Swapping can “commute” with a permutation. (Used in <a href="#proof-22">A.22</a>)</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="center" style="text-align: center"><mi>π</mi><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mi>π</mi></mtd></mtr><mtr><mtd columnalign="center" style="text-align: center"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="center" style="text-align: center"><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="center" style="text-align: center"><mo>=</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="center" style="text-align: center"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="center" style="text-align: center"><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mrow><mtext mathvariant="normal">case </mtext><mspace width="0.333em"></mspace></mrow><mi>x</mi><mo>=</mo><mi>a</mi></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mi>π</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mrow><mtext mathvariant="normal">case </mtext><mspace width="0.333em"></mspace></mrow><mi>x</mi><mo>=</mo><mi>b</mi></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mi>π</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable></mtd></mtr><mtr><mtd columnalign="center" style="text-align: center"><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mrow><mtext mathvariant="normal">case </mtext><mspace width="0.333em"></mspace></mrow><mi>x</mi><mo>≠</mo><mi>a</mi><mo>∧</mo><mi>x</mi><mo>≠</mo><mi>b</mi></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>≠</mo><mi>a</mi><mo>∧</mo><mi>x</mi><mo>≠</mo><mi>b</mi><mo>⟹</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>∧</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> — </mtext><mspace width="0.333em"></mspace></mrow><mi>π</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> injective</mtext></mrow><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mi>π</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{c}
\pi \circ (a \; b) = (\pi(a) \; \pi(b)) \circ \pi
\\ \; \\
(\pi \circ (a \; b))(x)
\\
= \pi((a \; b)(x))
\\ \; \\
\begin{aligned}
&amp; \text{case } x = a
\\
&amp; = \pi((a \; b)(a))
\\
&amp; = \pi(b)
\\
&amp; = (\pi(a) \; \pi(b))(\pi(a))
\\
&amp; = (\pi(a) \; \pi(b))(\pi(x))
\\
&amp; = ((\pi(a) \; \pi(b)) \circ \pi)(x)
\end{aligned}
\begin{aligned}
&amp; \text{case } x = b
\\
&amp; = \pi((a \; b)(b))
\\
&amp; = \pi(a)
\\
&amp; = (\pi(a) \; \pi(b))(\pi(b))
\\
&amp; = (\pi(a) \; \pi(b))(\pi(x))
\\
&amp; = ((\pi(a) \; \pi(b)) \circ \pi)(x)
\end{aligned}
\\
\begin{aligned}
&amp; \text{case } x \neq a \land x \neq b
\\
&amp; = \pi((a \; b)(x))
\\
&amp; = \pi(x)
\\
&amp; = (\pi(a) \; \pi(b))(\pi(x)) \; (x \neq a \land x \neq b \implies \pi(x) \neq \pi(a) \land \pi(x) \neq \pi(b) \text{ --- } \pi \text{ injective})
\\
&amp; = ((\pi(a) \; \pi(b)) \circ \pi)(x)
\end{aligned}
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-22"><a href="#proof-22">Proof 22</a></h2>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mo stretchy="false" form="prefix">(</mo><mi>−</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">[\mathbb{A}]({-})</annotation></semantics></math> is right adjoint to the functor <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow></mrow><mo>−</mo><mi>*</mi><mspace width="0.278em"></mspace><mi>𝔸</mi></mrow><annotation encoding="application/x-tex">{}- * \; \mathbb{A}</annotation></semantics></math> arising from the following
nominal set: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>X</mi><mo>*</mo><mi>𝔸</mi><mo>=</mo><mo stretchy="false" form="prefix">{</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mi>x</mi><mo>∈</mo><mi>X</mi><mo>,</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="postfix">}</mo></mrow><annotation encoding="application/x-tex">X * \mathbb{A} = \{ \; (x, a) \; | \; x \in X, a \; \# \; x  \;\}</annotation></semantics></math>. <a href="nominal-sets#proof-22-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mrow></mrow><mo>−</mo><mi>*</mi><mspace width="0.278em"></mspace><mi>𝔸</mi><mo>⊣</mo><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mo stretchy="false" form="prefix">(</mo><mi>−</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">bind</mtext><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>X</mi><mo>*</mo><mspace width="0.278em"></mspace><mi>𝔸</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>Y</mi><mo stretchy="false" form="postfix">)</mo><mo>→</mo><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mo stretchy="false" form="prefix">(</mo><mi>Y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">bind</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> for some </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><msup><mtext mathvariant="normal">bind</mtext><mrow><mi>−</mi><mn>1</mn></mrow></msup><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mo stretchy="false" form="prefix">(</mo><mi>Y</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>→</mo><mi>X</mi><mo>*</mo><mspace width="0.278em"></mspace><mi>𝔸</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>Y</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><msup><mtext mathvariant="normal">bind</mtext><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>@</mi><mspace width="0.278em"></mspace><mi>a</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mtext mathvariant="normal">where</mtext></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>−</mo><mrow></mrow><mspace width="0.278em"></mspace><mi>@</mi><mo>−</mo><mrow></mrow><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mi>X</mi><mo>*</mo><mi>𝔸</mi><mo>→</mo><mi>X</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mi>@</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><msup><mi>a</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
{}- * \; \mathbb{A} \dashv [\mathbb{A}]({-}) 
\\ \; \\
\text{bind} \; : \;
(X * \; \mathbb{A} \rightarrow_{Nom} Y) \rightarrow 
X \rightarrow_{Nom} [\mathbb{A}](Y)
\\
\text{bind}(f)(x) = \langle a \rangle f(x, a) \text{ for some } a \; \# \; x
\\ \; \\
\text{bind}^{-1} \; : \; 
(X \rightarrow_{Nom} [\mathbb{A}](Y)) \rightarrow
X * \; \mathbb{A} \rightarrow_{Nom} Y
\\
\text{bind}^{-1}(f)(x, a) = f(x) \; @ \; a
\\
\; \; \text{where}
\\
\; \; \; \; -{} \; @ -{} \; : \; [\mathbb{A}]X * \mathbb{A} \rightarrow X
\\
\; \; \; \; @(\langle a \rangle x, a&#39;) = (a \; a&#39;) \cdot x
\end{array}
</annotation></semantics></math></p>
<p><br></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">bind</mtext><mo stretchy="false" form="prefix">(</mo><msup><mtext mathvariant="normal">bind</mtext><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mspace width="0.278em"></mspace><msup><mtext mathvariant="normal">bind</mtext><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> for some </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>@</mi><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>@</mi><mspace width="0.278em"></mspace><mi>a</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> requires </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mo>∧</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>f</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> equivariant – A.14</mtext></mrow><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">A.10</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mrow><mtext mathvariant="normal">let </mtext><mspace width="0.333em"></mspace></mrow><mo stretchy="false" form="prefix">⟨</mo><msup><mi>a</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">⟩</mo><msup><mi>x</mi><mo>′</mo></msup><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><msup><mi>a</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">⟩</mo><msup><mi>x</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>@</mi><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⇔</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><msup><mi>a</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">⟩</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⇔</mo><mi>a</mi><mo>=</mo><msup><mi>a</mi><mo>′</mo></msup><mo>∨</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mrow><mtext mathvariant="normal">case </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><mo>=</mo><msup><mi>a</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><msup><mi>a</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">⟩</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><msup><mi>a</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><msup><mi>a</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">⟩</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mrow><mtext mathvariant="normal">case </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>∀</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo>,</mo><msup><mi>x</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⇔</mo><mo>∀</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo>,</mo><msup><mi>x</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⇔</mo><mo>∀</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo>,</mo><msup><mi>x</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo>∘</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>π</mi><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>∘</mo><mi>π</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> — A.21</mtext></mrow><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⇔</mo><mo>∀</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo>,</mo><msup><mi>x</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⇔</mo><mo>∀</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo>,</mo><msup><mi>x</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><msup><mi>x</mi><mo>′</mo></msup><mo>∧</mo><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><msup><mi>x</mi><mo>′</mo></msup><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mo>=</mo><msup><mi>x</mi><mo>′</mo></msup><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> — A.9</mtext></mrow><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>⇔</mo><mo>∃</mo><mi>b</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>,</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo>,</mo><msup><mi>x</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mo>∧</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><msup><mi>x</mi><mo>′</mo></msup><mo>∧</mo><mi>b</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><msup><mi>x</mi><mo>′</mo></msup><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup><mo>=</mo><msup><mi>x</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">A.13</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mo stretchy="false" form="prefix">⟨</mo><msup><mi>a</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">⟩</mo><msup><mi>x</mi><mo>′</mo></msup></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{bind}(\text{bind}^{-1}(f))(x)
\\
= \langle a \rangle \; \text{bind}^{-1}(f)(x, a)
\text{ for some } a \; \# \; x
\\
= \langle a \rangle \; (f(x) \; @ \; a)
\\
\; \; \; \; f(x) \; @ \; a \text{ requires } a \; \# \; f(x)
\\
\; \; \; \; \; \; \; \; a \; \# \; x \land a \; \# \; f \; (f \text{ equivariant -- A.14}) \implies a \; \# \; f(x) \; (\text{A.10})
\\
\; \; \; \; \text{let } \langle a&#39; \rangle x&#39; = f(x)
\\
= \langle a \rangle (\langle a&#39; \rangle x&#39; \; @ \; a)
\\
= \langle a \rangle \; (a&#39; \; a) \cdot x&#39;
\\ \; \\
\; \; \; \; a \; \# f(x)
\\
\; \; \; \; \iff a \; \# \; \langle a&#39; \rangle x&#39;
\\
\; \; \; \; \iff a = a&#39; \lor a \; \# \; x&#39;
\\ \; \\
\; \; \; \; \text{case } a = a&#39;
\\
\; \; \; \; \; \; \; \; \langle a \rangle \; (a&#39; \; a) \cdot x&#39;
\\
\; \; \; \; \; \; \; \; = \langle a&#39; \rangle \; (a&#39; \; a&#39;) \cdot x&#39;
\\
\; \; \; \; \; \; \; \; = \langle a&#39; \rangle x&#39;
\\
\; \; \; \; \; \; \; \; = f(x)
\\ \; \\
\; \; \; \; \text{case } a \; \# \; x&#39;
\\
\; \; \; \; \; \; \; \; \forall b. \; b \; \# \; (a, (a&#39; \; a) \cdot x&#39;, a&#39;, x&#39;) \implies (a \; b) \cdot (a&#39; \; a) \cdot x&#39; = (a&#39; \; b) \cdot x&#39;
\\
\; \; \; \; \; \; \; \; \iff \forall b. \; b \; \# \; (a, (a&#39; \; a) \cdot x&#39;, a&#39;, x&#39;) \implies ((a \; b) \circ (a&#39; \; a)) \cdot x&#39; = (a&#39; \; b) \cdot x&#39;
\\
\; \; \; \; \; \; \; \; \iff \forall b. \; b \; \# \; (a, (a&#39; \; a) \cdot x&#39;, a&#39;, x&#39;) \implies ((a&#39; \; b) \circ (a \; b)) \cdot x&#39; = (a&#39; \; b) \cdot x&#39; \; (\pi \circ (a \; b) = (\pi(a) \; \pi(b)) \circ \pi \text{ --- A.21})
\\
\; \; \; \; \; \; \; \; \iff \forall b. \; b \; \# \; (a, (a&#39; \; a) \cdot x&#39;, a&#39;, x&#39;) \implies (a&#39; \; b) \cdot (a \; b) \cdot x&#39; = (a&#39; \; b) \cdot x&#39;
\\
\; \; \; \; \; \; \; \; \iff \forall b. \; b \; \# \; (a, (a&#39; \; a) \cdot x&#39;, a&#39;, x&#39;) \implies (a&#39; \; b) \cdot x&#39; = (a&#39; \; b) \cdot x&#39; \; (a \; \# \; x&#39; \land b \; \# \; x&#39; \implies (a \; b) \cdot x&#39; = x&#39; \text{ --- A.9})
\\
\; \; \; \; \; \; \; \; \iff \exists b. \; b \; \# \; (a, (a&#39; \; a) \cdot x&#39;, a&#39;, x&#39;) \land (a&#39; \; b) \cdot x&#39; = (a&#39; \; b) \cdot x&#39; \; (a \; \# \; x&#39; \land b \; \# \; x&#39; \implies (a \; b) \cdot x&#39; = x&#39; \; (\text{A.13})
\\ \; \\
\; \; \; \; \; \; \; \; \langle a \rangle \; (a&#39; \; a) \cdot x&#39;
\\
\; \; \; \; \; \; \; \; = \langle a&#39; \rangle x&#39;
\\
\; \; \; \; \; \; \; \; = f(x)
\end{array}
</annotation></semantics></math></p>
<p><br></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><msup><mtext mathvariant="normal">bind</mtext><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">bind</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> where </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mtext mathvariant="normal">bind</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>@</mi><mspace width="0.278em"></mspace><mi>a</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mtext mathvariant="normal">bind</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>@</mi><mspace width="0.278em"></mspace><mi>a</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> requires </mtext><mspace width="0.333em"></mspace></mrow><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mtext mathvariant="normal">bind</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mspace width="0.278em"></mspace><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mo>∧</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mtext mathvariant="normal">bind</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">bind(f)</mtext><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> equivariant – A.14</mtext></mrow><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mtext mathvariant="normal">bind</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">A.10</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><msup><mi>a</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">⟩</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> for some </mtext><mspace width="0.333em"></mspace></mrow><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mi>@</mi><mspace width="0.278em"></mspace><mi>a</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><msup><mi>a</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>,</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><msup><mi>a</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mspace width="0.278em"></mspace><mtext mathvariant="normal">equivariant</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>,</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>,</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mo>∧</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>x</mi><mo>⟹</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>a</mi><mo>′</mo></msup><mspace width="0.278em"></mspace><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>x</mi><mo>=</mo><mi>x</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> — A.9</mtext></mrow><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{bind}^{-1}(\text{bind}(f))(x, a) \text{ where } a \; \# \; x
\\
= \text{bind}(f)(x) \; @ \; a
\\
\; \; \; \; \text{bind}(f)(x) \; @ \; a \text{ requires } a \; \# \; \text{bind}(f)(x)
\\
\; \; \; \; a \; \# \; x \land a \; \# \; \text{bind}(f) \; (\text{bind(f)} \text{ equivariant -- A.14}) \implies a \; \# \; \text{bind}(f)(x) \; (\text{A.10})
\\
= (\langle a&#39; \rangle f(x, a&#39;) \text{ for some } a&#39; \; \# \; x) \; @ \; a \\
= (a&#39; \; a) \cdot f(x, a&#39;)
\\
= f((a&#39; \; a) \cdot x, (a&#39; \; a) \cdot a&#39;) \; (f \; \text{equivariant})
\\
= f((a&#39; \; a) \cdot x, a)
\\
= f(x, a) \; (a&#39; \; \# \; x \land a \; \# \; x \implies (a&#39; \; a) \cdot x = x \text{ --- A.9})
\end{array}
</annotation></semantics></math></p>
<h2 id="proof-23"><a href="#proof-23">Proof 23</a></h2>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mo stretchy="false" form="prefix">(</mo><mi>−</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">[\mathbb{A}]({-})</annotation></semantics></math> is left adjoint to this functor:
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>R</mi><mo stretchy="false" form="prefix">(</mo><mi>Y</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">{</mo><mspace width="0.278em"></mspace><mi>f</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mi>f</mi><mo>∈</mo><msup><mi>Y</mi><mi>𝔸</mi></msup><mo>,</mo><mspace width="0.278em"></mspace><mo>∀</mo><mi>a</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="postfix">}</mo></mrow><annotation encoding="application/x-tex">R(Y) = \{ \; f \; | \; f \in Y^{\mathbb{A}}, \; \forall a. \; a \; \# \; f(a) \;
\}</annotation></semantics></math>. <a href="nominal-sets#proof-23-link">↩︎</a></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mo stretchy="false" form="prefix">(</mo><mi>−</mi><mrow></mrow><mo stretchy="false" form="postfix">)</mo><mo>⊣</mo><mi>R</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">unbind</mtext><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>R</mi><mo stretchy="false" form="prefix">(</mo><mi>Y</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo>→</mo><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>Y</mi></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">unbind</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><msup><mtext mathvariant="normal">unbind</mtext><mrow><mi>−</mi><mn>1</mn></mrow></msup><mspace width="0.278em"></mspace><mo>:</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">[</mo><mi>𝔸</mi><mo stretchy="false" form="postfix">]</mo><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>Y</mi><mo stretchy="false" form="postfix">)</mo><mo>→</mo><mi>X</mi><msub><mo>→</mo><mrow><mi>N</mi><mi>o</mi><mi>m</mi></mrow></msub><mi>R</mi><mo stretchy="false" form="prefix">(</mo><mi>Y</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><msup><mtext mathvariant="normal">unbind</mtext><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>λ</mi><mi>a</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
[\mathbb{A}](-{}) \dashv R
\\ \; \\
\text{unbind} \; : \; (X \rightarrow_{Nom} R(Y)) \rightarrow [\mathbb{A}] X \rightarrow_{Nom} Y
\\
\text{unbind}(f)(\langle a \rangle x) = f(x)(a)
\\ \; \\
\text{unbind}^{-1} \; : \; ([\mathbb{A}] X \rightarrow_{Nom} Y) \rightarrow X \rightarrow_{Nom} R(Y)
\\
\text{unbind}^{-1}(f)(x) = \lambda a. \; f(\langle a \rangle x)
\end{array}
</annotation></semantics></math></p>
<p><br></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><msup><mtext mathvariant="normal">unbind</mtext><mrow><mi>−</mi><mn>1</mn></mrow></msup><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> requires </mtext><mspace width="0.333em"></mspace></mrow><mo>∀</mo><mi>a</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><msup><mi>a</mi><mo>′</mo></msup><mi>.</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><msup><mi>a</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mspace width="0.278em"></mspace></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>∀</mo><mi>a</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><msup><mi>a</mi><mo>′</mo></msup><mi>.</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><msup><mi>a</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>⇔</mo><mo>∀</mo><mi>a</mi><mi>.</mi><mspace width="0.278em"></mspace><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>f</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> equivariant – A.14</mtext></mrow><mo stretchy="false" form="postfix">)</mo><mo>∧</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>=</mo><mi>b</mi><mo>⟹</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">⟨</mo><mi>b</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> — A.12</mtext></mrow><mo stretchy="false" form="postfix">)</mo><mo>⟹</mo><mi>a</mi><mspace width="0.278em"></mspace><mi>#</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">A.10</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{unbind}^{-1} \text{ requires } \forall a. \; a \; \# \; (\lambda a&#39;. \; f(\langle a&#39; \rangle x))(a)
\\ \; \\
\forall a. \; a \; \# \; (\lambda a&#39;. \; f(\langle a&#39; \rangle x))(a)
\\
\iff \forall a. \; a \; \# \; f(\langle a \rangle x)
\\
a \; \# \; f \; (f \text{ equivariant -- A.14}) \land a \; \# \; \langle a \rangle x \; (a = b \implies a \; \# \; \langle b \rangle x \text{ --- A.12}) \implies a \; \# \; f(\langle a \rangle x) \; (\text{A.10})
\end{array}
</annotation></semantics></math></p>
<p><br></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">unbind</mtext><mo stretchy="false" form="prefix">(</mo><msup><mtext mathvariant="normal">unbind</mtext><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><msup><mtext mathvariant="normal">unbind</mtext><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>λ</mi><msup><mi>a</mi><mo>′</mo></msup><mi>.</mi><mspace width="0.278em"></mspace><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><msup><mi>a</mi><mo>′</mo></msup><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>β</mi><mtext mathvariant="normal">-equivalence</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{unbind}(\text{unbind}^{-1}(f))(\langle a \rangle x)
\\
= \text{unbind}^{-1}(f)(x)(a)
\\
= (\lambda a&#39;. \; f(\langle a&#39; \rangle x))(a)
\\
= f(\langle a \rangle x) \; (\beta \text{-equivalence})
\end{array}
</annotation></semantics></math></p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="left" style="text-align: left"><msup><mtext mathvariant="normal">unbind</mtext><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">unbind</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>λ</mi><mi>a</mi><mi>.</mi><mspace width="0.278em"></mspace><mtext mathvariant="normal">unbind</mtext><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⟨</mo><mi>a</mi><mo stretchy="false" form="postfix">⟩</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>λ</mi><mi>a</mi><mi>.</mi><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mo>=</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">(</mo><mi>η</mi><mtext mathvariant="normal">-equivalence</mtext><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{array}{l}
\text{unbind}^{-1}(\text{unbind}(f))(x)
\\
= \lambda a. \; \text{unbind}(f)(\langle a \rangle x)
\\
= \lambda a. f(x)(a)
\\
= f(x) \; (\eta \text{-equivalence})
\end{array}
</annotation></semantics></math></p>
    ]]></content>
    
</entry>
<entry>
    <title>Gear Acquisition Syndrome</title>
    <link href="https://blog.ielliott.io/gear-acquisition-syndrome" />
    
    <id>https://blog.ielliott.io/gear-acquisition-syndrome</id>
    
    <published>2023-05-28T06:36:00Z</published>
    <updated>2023-05-28T06:36:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/gear-acquisition-syndrome"><![CDATA[<p>Over the past few years I’ve become wary of a certain feeling related to my artistic hobbies
like drawing and music production: the sense of excitement and “motivation” after I’ve acquired
some new art-related material. It’s very easy to spend hours doodling with a new marker, writing
in a fresh journal, or twiddling with a synth I’ve just bought. The next day, though, the new tool
is a little less exciting, and so on, until it’s as normal as everything else.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/gear-acquisition-syndrome"><![CDATA[
      
      <p>Over the past few years I’ve become wary of a certain feeling related to my artistic hobbies
like drawing and music production: the sense of excitement and “motivation” after I’ve acquired
some new art-related material. It’s very easy to spend hours doodling with a new marker, writing
in a fresh journal, or twiddling with a synth I’ve just bought. The next day, though, the new tool
is a little less exciting, and so on, until it’s as normal as everything else.</p>
<p>In situations like these it seems easy to mistake the excitement of novelty for actual interest
in an artistic process. I find it kind of scary to imagine accidentally convincing myself that
creativity and motivation follows from having bought something new. Here’s an
<a href="https://en.wikipedia.org/wiki/Archetype">archetypal</a>
story of a situation I’m trying to avoid, based on my experiences with this subject across a
few hobbies:</p>
<blockquote>
<p>Painting is a large part of my identity. I think of myself as <em>a painter</em>,
and the idea that I create paintings is almost existentially important to me. If I’m a painter and I don’t paint,
then <em>what even am I</em>? There’s one problem: I haven’t painted anything in months. These days I never have any good ideas,
and I’m rarely inspired or motivated to pick up a brush. One day I stumble across a video of someone painting with
<a href="https://en.wikipedia.org/wiki/Gouache">gouache</a>. I feel something when I see that painting (inspiration, maybe?)
and I’ve never used gouache before, so I head out to the art store to buy some. I arrive home excited to try these
new paints. In the hours that follow I have fun fooling around, and the part of me that sees myself as a painter
is satisfied: I’m doing the thing that I’m supposed to be doing. As days and weeks pass the excitement fades, and
the pressures of everyday life eclipse my painting practise. One day I realise that I haven’t painted anything for a
while. This realisation is as uncomfortable as ever: I <em>am</em> a painter, so if I haven’t been painting then what have
I been doing with myself? I jump on Instagram to look for some inspiration, and the cycle repeats.</p>
</blockquote>
<p>There’s a lot going on there: <a href="https://en.wikipedia.org/wiki/Self-concept">self-concept</a>, motivation,
shame, creativity, and <a href="https://en.wikipedia.org/wiki/Operant_conditioning">conditioning</a> all interacting.
Right now I’m most interested in the way “getting new stuff” relates to motivation and creativity.</p>
<h2 id="gas"><a href="#gas">G.A.S.</a></h2>
<p>This topic came to mind recently after reading
<a href="https://registerspill.thorstenball.com/p/when-the-cymbals-come-in">“When the Cymbals Come In” by Thorsten Ball</a>
where I was introduced to the term “Gear Acquisition Syndrome” (GAS). The blurb of
<a href="https://unipress.hud.ac.uk/plugins/books/27/">“Gear Acquisition Syndrome: Consumption of Instruments and Technology in Popular Music” by Jan-Peter Herbst &amp; Jonas Menze</a>
defines it very nicely:</p>
<blockquote>
<p>Gear Acquisition Syndrome, also known as GAS, is commonly understood as the musicians’ unrelenting urge
to buy and own instruments and equipment as an anticipated catalyst of creative energy and bringer of happiness.</p>
</blockquote>
<p>Parts of GAS describe the relationship toward my tools that I’ve been trying to avoid. It’s
relieving to find a concise, searchable term that gets me into the same “informational neighbourhood”. I found two
interesting articles while exploring the topic through Google:</p>
<ul>
<li><p><a href="http://sdarchive.com/gas.html">G.A.S.</a> by <a href="https://en.wikipedia.org/wiki/Walter_Becker">Walter Becker</a></p>
<p><a href="https://www.guitarworld.com/features/gear-acquisition-syndrome">This Guitar World article</a> suggests that this
essay from 1996 popularised the terms “Gear Acquisition Syndrome” and “GAS”.</p></li>
<li><p><a href="https://www.joshuasarinana.com/the-science-of-gear-acquisition-syndrome">“The Science of Gear Acquisition Syndrome” by Joshua Sariñana</a></p>
<p>A neuroscientific, psychological, and slightly philosophy take on GAS from a photography perspective. I most
enjoyed their take on the relationship between creativity and anxiety. Stress, fear, and shame around creative projects
lead to <a href="https://en.wikipedia.org/wiki/Avoidance_coping">avoidance</a><a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>, and “gear acquisition” temporarily masks
these emotions with a burst of excitement.</p></li>
</ul>
<h2 id="what-to-do-about-it"><a href="#what-to-do-about-it">What to do about it?</a></h2>
<p>I have some <a href="https://en.wikipedia.org/wiki/Heuristic">heuristics</a> to avoid GAS. I don’t always follow them (but I hope
that writing them down will increase my accountability to the idea), and being heuristics they necessarily don’t work
for every situation. I’ll present them here as advice to my future selves.</p>
<h3 id="do-the-thing-a-lot"><a href="#do-the-thing-a-lot">Do the thing a lot</a></h3>
<p>Demonstrate a commitment to the activity before you think about buying anything to support it. I place a lot of
weight on <a href="https://blog.ielliott.io/learning-a-craft#find-joy-in-the-process">enjoying the process</a>, and when trying
something new it’s easy to confuse the excitement of novelty with enjoyment of the activity. New toys compounds this.
In the beginning it’s more important to make a habit out of the activity, or discover that you don’t actually like it.</p>
<p>Example: You’ve just started rock climbing with friends. Use the rental shoes at the climbing gym for a few months before
buying your own.</p>
<h3 id="wear-it-out"><a href="#wear-it-out">Wear it out</a></h3>
<p>One measure of commitment to an activity is whether you’re wearing out my gear and using up your materials.
It’s important that this stays a <em>measure</em>, rather than a <em>target</em>, in the sense of
<a href="https://en.wikipedia.org/wiki/Goodhart%27s_law">Goodhart’s Law</a>: “When a measure becomes a target, it ceases to be a good measure.”</p>
<p>Example: You use your cheap stand mixer at least twice a week and it’s starting to fall apart. It’s time to
think about getting a higher-quality model.</p>
<h3 id="keep-it-simple"><a href="#keep-it-simple">Keep it simple</a></h3>
<p>If you physically need gear to do the thing, start with cheap gear and keep research to the minimum. As a beginner
you can’t percieve most of the differences between similar tools. Perceptual ability and taste only develop as your
skills improve. It’s easy to get caught in <a href="https://en.wikipedia.org/wiki/Analysis_paralysis">“analysis paralysis”</a>,
comparing gear that would be indistinguishable to you in practise.</p>
<p>Example: You want to learn guitar. Use the crappy hand-me-down that your friend is giving away instead of buying
your favourite player’s signature model.</p>
<h3 id="relief-over-excitement"><a href="#relief-over-excitement">Relief over excitement</a></h3>
<p>As you become committed to an activity and your skills improve, you will start to notice <em>real</em> flaws and limitations
in your current tools. These are no reason to stop doing the thing, and you can usually continue to improve without
addressing them. At this point the experience you’ve gained will suggest <em>specific</em> properties you need from a different
tool to overcome the limitations of your current one. Crappy gear or not, you are going to do the thing anyway. So when
you finally get the better tool, you mostly feel relief from the benefits of using it, rather than excitement or “inspiration”
<em>to</em> use it.</p>
<p>Example: Having played tennis weekly for the past 6 months with clunky hire racquets, you appreciate how light
and responsive your new one feels while playing.</p>
<h2 id="postscript"><a href="#postscript">Postscript</a></h2>
<p>When I told my girlfriend about “Gear Acquisition Syndrome”, she taught me a
Chinese phrase that has a similar meaning: “<span lang="zh">差生文具多</span>”, which literally means “the poor student
has lots of stationery”. It’s inspired by a hypothetical student who is not studying enough, so to
get more motivation they go shopping for stationery (instead of studying). A student who does well,
on the other hand, can study at any time with the simplest of materials. The phrase is an internet meme in China
and we watched a few funny videos about gym-goers with too much fitness gear, home cooks with too many pots, and so on.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>See also: <a href="https://www.lesswrong.com/posts/EFQ3F6kmt4WHXRqik/ugh-fields">“Ugh Fields”</a><a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
    ]]></content>
    
</entry>
<entry>
    <title>Migrating from Jekyll to Hakyll</title>
    <link href="https://blog.ielliott.io/jekyll-to-hakyll" />
    
    <id>https://blog.ielliott.io/jekyll-to-hakyll</id>
    
    <published>2023-05-04T00:00:00Z</published>
    <updated>2023-05-04T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/jekyll-to-hakyll"><![CDATA[<p>I’ve just finished migrating this site from <a href="https://jekyllrb.com/">Jekyll</a> to
<a href="https://jaspervdj.be/hakyll/">Hakyll</a>. The only noticeable changes are: <em>slightly</em> prettier page URLs, MathML support, and
tweaks to syntax highlighting to compensate for using <a href="https://pandoc.org">Pandoc</a>. I paid
special attention to preserving the <a href="/feed.xml">Atom feed</a> identifiers so that feed readers aren’t
impacted.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/jekyll-to-hakyll"><![CDATA[
      
      <div id="toc">
<h3>Contents</h3>
<ul>
<li><a href="#background">Background</a></li>
<li><a href="#changes">Changes</a>
<ul>
<li><a href="#prettier-urls">Prettier URLs</a></li>
<li><a href="#mathml-support">MathML support</a></li>
<li><a href="#syntax-highlighting">Syntax highlighting</a></li>
</ul></li>
<li><a href="#thoughts">Thoughts</a></li>
</ul>
</div>
<p>I’ve just finished migrating this site from <a href="https://jekyllrb.com/">Jekyll</a> to
<a href="https://jaspervdj.be/hakyll/">Hakyll</a>. The only noticeable changes are: <em>slightly</em> prettier page URLs, MathML support, and
tweaks to syntax highlighting to compensate for using <a href="https://pandoc.org">Pandoc</a>. I paid
special attention to preserving the <a href="/feed.xml">Atom feed</a> identifiers so that feed readers aren’t
impacted.</p>
<p>You can find the source code at <a href="https://github.com/LightAndLight/lightandlight.github.io/" class="uri">https://github.com/LightAndLight/lightandlight.github.io/</a>.</p>
<h2 id="background"><a href="#background">Background</a></h2>
<p>I’ve been using Jekyll to generate my blog because that’s what <a href="https://pages.github.com/">GitHub
Pages</a> recommended when I first set things up. Recently I’ve been working
on a math-heavy post, and I decided that I wanted <a href="https://developer.mozilla.org/en-US/docs/Web/MathML">MathML</a>
support for this site. I started exploring possible solutions, and found <a href="https://github.com/jgm/texmath"><code>texmath</code></a>,
which I then learned is used in <a href="https://pandoc.org/">Pandoc</a> to <a href="https://pandoc.org/MANUAL.html#math-rendering-in-html">convert TeX to
MathML</a>. I know Hakyll has good Pandoc support, and
Haskell is one of my main languages, so I decided to make the switch<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>.</p>
<h2 id="changes"><a href="#changes">Changes</a></h2>
<h3 id="prettier-urls"><a href="#prettier-urls">Prettier URLs</a></h3>
<p>Change: removed trailing slashes from many blog page URLs (e.g.
from <code>https://blog.ielliott.io/test-post/</code> to <code>https://blog.ielliott.io/test-post</code>).</p>
<p>Static site generators create HTML files, which typically have file paths ending in <code>.html</code>. Web servers
often map URL paths to filesystem paths to serve files, leading to many URLs ending in
<code>.html</code>. I don’t like this; <code>.html</code> offers me no useful
information. And if it <em>does</em> coincide with the resource’s file
type, <a href="https://www.w3.org/DesignIssues/NameMyth.html#Why">that is subject to change</a>.</p>
<p>My Jekyll-based site had “extension-less URLs” (which I call “pretty URLs”), but I
consistently used a trailing slash at the end of every URL (e.g.
<code>https://blog.ielliot.io/test-post/</code>). These days I prefer to use a trailing
slash to signify a “directory-like resource”, under which other resources are “nested”. This aligns with the convention where web servers serve <code>/index.html</code> when <code>/</code> is
requested. My blog posts don’t need an index because they’re self contained, so their URLs shouldn’t
have a trailing slash.</p>
<p><a href="https://rsp.github.io/gh-pages-no-extension/index">GitHub Pages supports extensionless HTML pages</a>,
serving file <code>x.html</code> when <code>x</code> is requested, so I removed the trailing slash from each page’s
canonical path and make Hakyll generate a file ending in <code>.html</code> at that path
(<a href="https://github.com/LightAndLight/lightandlight.github.io/blob/a29bac1b084b86abe43e28c4062ca963d0647b98/site.hs#L127"><code>site.hs#L127</code></a>,
<a href="https://github.com/LightAndLight/lightandlight.github.io/blob/a29bac1b084b86abe43e28c4062ca963d0647b98/site.hs#L322-L333"><code>site.hs#L322-L333</code></a>).</p>
<p>By default, Hakyll’s <code>watch</code> command doesn’t support pretty URLs. For a little while, I manually
added <code>.html</code> to the URL in the address bar whenever I clicked a link in my site’s preview. I got sick of
this and changed the configuration to resemble GitHub Pages’ pretty URL resolution rules
(<a href="https://github.com/LightAndLight/lightandlight.github.io/blob/a29bac1b084b86abe43e28c4062ca963d0647b98/site.hs#L30-L55"><code>site.hs#L30-L55</code></a>).
I realised how fortunate it was that I could make this change; the relevant Hakyll changes were only
<a href="https://hackage.haskell.org/package/hakyll/changelog#hakyll-41600-2023-04-27">released a week ago!</a></p>
<h3 id="mathml-support"><a href="#mathml-support">MathML support</a></h3>
<p>Changes:</p>
<ul>
<li>Equations are compiled to MathML</li>
<li>MathJax is never automatically loaded</li>
<li>Browsers with poor MathML support display a warning and some options for improvement</li>
</ul>
<p>I’m becoming more aware of sites that use unnecessary JavaScript. I realised that my blog’s use of
MathJax for client-side equation rendering was an example of this. The equations on my blog are static; all the information required to
render them is present when I generate the site, so I should be able to compile the equations once and
serve them to readers. Client-side MathJax is
better suited for fast feedback on dynamic equations, like when someone types an equation into a text
box.</p>
<p>I played with compiling LaTeX equations to SVGs
(<a href="https://github.com/LightAndLight/latex4web/blob/552cf33a02b9644ca4cd6987d920af88e2759e95/latex2svg.py"><code>latex2svg.py</code></a>,
<a href="https://github.com/LightAndLight/latex4web/blob/552cf33a02b9644ca4cd6987d920af88e2759e95/latex2svg.m4"><code>latex2svg.m4</code></a>),
but realised it would be hard to make that
<a href="https://www.w3.org/WAI/fundamentals/accessibility-intro/">accessible</a>. I then
came across <a href="https://developer.mozilla.org/en-US/docs/Web/MathML">MathML</a> and realised that it was the right solution.</p>
<p>MathML <a href="https://caniuse.com/mathml">still isn’t ubiquitous</a>, so I added a <a href="https://github.com/LightAndLight/lightandlight.github.io/blob/2124670c349ce879a441ea01b19cbdfe42c031bf/js/mathml-polyfill.js">polyfill
script</a>
based on <a href="https://github.com/fred-wang/mathml-warning.js" class="uri">https://github.com/fred-wang/mathml-warning.js</a>. If you view
a math post in a web browser with limited MathML support, you’ll be prompted to
improve the experience by loading external resources:</p>
<p><img src="./images/mathml-warning.png" alt="Screenshot of a warning message for browsers with poor
MathML support. The warning says, &quot;This page uses MathML, which your browser doesn't fully
support.&quot; Below that, there are 3 options: &quot;Load MathJax&quot; (currently selected), &quot;Apply
mathml.css&quot;, and &quot;Do nothing&quot;. Under those, there is a checkbox (unchecked) labelled
&quot;Remember choice for 30 days&quot;. At the bottom, there are two buttons: &quot;Ignore&quot;
and &quot;Save&quot;." style="max-width: 100%" /></p>
<h3 id="syntax-highlighting"><a href="#syntax-highlighting">Syntax highlighting</a></h3>
<p>Change: slightly different syntax highlighting.</p>
<p>Pandoc does syntax highlighting differently to Jekyll, and I prefer Jekyll’s output. I’ll explain
why in another post. The consequence is that I had to rewrite my syntax highlighting stylesheet, and
code might look a little different due to the way Pandoc marks it up.</p>
<h2 id="thoughts"><a href="#thoughts">Thoughts</a></h2>
<p>I had to reimplement a few things that Jekyll did for
me, like the <a href="/sitemap.xml">sitemap</a>
(<a href="https://github.com/LightAndLight/lightandlight.github.io/blob/a29bac1b084b86abe43e28c4062ca963d0647b98/site.hs#L196-L206"><code>site.hs#L196-206</code></a>)
and previous/next post links
(<a href="https://github.com/LightAndLight/lightandlight.github.io/blob/a29bac1b084b86abe43e28c4062ca963d0647b98/site.hs#L240-L260"><code>site.hs#L240-L260</code></a>).
I didn’t have to create the Atom feed from scratch, though: <a href="https://hackage.haskell.org/package/hakyll-4.16.0.0/docs/Hakyll-Web-Feed.html">Hakyll has a module for that</a>. The whole process was pretty involved (a few days of work) and I
think I only had the appetite for it because I’m currently not working.</p>
<p>This is the most time I’ve spent working on a Hakyll site, and I think I’ve crossed an “inflection
point” in my understanding of the library. I can now build features from scratch instead of searching for recipes on the internet. Normally I would approach a static site generator with some impatience,
wanting to “get things done” so that I can return to what I find interesting. This time around, I
decided to do a deep dive and I gained a lot of experience.</p>
<p>I’m glad I made the switch. While Pandoc has a few annoying issues, I’m not
discouraged from fixing them like I would be if I found a problem with Jekyll.
Being proficient with Haskell, fixing these issues would just be a variation on normal software
development for me.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Also, there were no satisfying search results for how to do this with Jekyll.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
    ]]></content>
    
</entry>
<entry>
    <title>Web Resources I Enjoy</title>
    <link href="https://blog.ielliott.io/web-resources-i-enjoy" />
    
    <id>https://blog.ielliott.io/favourites</id>
    
    <published>2023-01-10T00:00:00Z</published>
    <updated>2023-01-10T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/web-resources-i-enjoy"><![CDATA[<p>In
<a href="https://www.samharris.org/podcasts/making-sense-episodes/304-why-i-left-twitter">this
conversation</a>,
<a href="https://www.samharris.org">Sam Harris</a> and <a href="https://www.calnewport.com">Cal Newport</a> talked about
how we use the world wide web, how it has become extremely centralised around a few social media
platforms, and the role of recommendation algorithms in this system. Parts of this conversation are
starting to influence the way I use the web.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/web-resources-i-enjoy"><![CDATA[
      
      <p>In
<a href="https://www.samharris.org/podcasts/making-sense-episodes/304-why-i-left-twitter">this
conversation</a>,
<a href="https://www.samharris.org">Sam Harris</a> and <a href="https://www.calnewport.com">Cal Newport</a> talked about
how we use the world wide web, how it has become extremely centralised around a few social media
platforms, and the role of recommendation algorithms in this system. Parts of this conversation are
starting to influence the way I use the web.</p>
<p>Recommendation algorithms on social media don’t optimise for general human flourishing.
They maximise metrics like engagement, views, clicks, or comments. To social media, all engagement is good,
regardless of its impact on your life.</p>
<p>Before centralised social media, we had a very organic recommendation system.
You read the blogs of people who you thought were interesting, and they linked
to sites that they thought were interesting, and you would follow some of those links and find new
content for yourself. In this organic system, <em>we</em> are the recommenders.
We can “optimise” our recommendations for things that are highly personal and very difficult to
measure, like curiosity, wonder, awe, learning, and insight.</p>
<p>I’d like to contribute to a more distributed, personalised, and organic world wide web, so I’ve
created a <a href="/resources">resources page</a>. I’ll continue to add various web resources that I find
interesting, in the hope that others might use it to find something new.</p>
    ]]></content>
    
</entry>
<entry>
    <title>2022 Project Review</title>
    <link href="https://blog.ielliott.io/2022-project-review" />
    
    <id>https://blog.ielliott.io/project-review</id>
    
    <published>2022-12-27T04:25:00Z</published>
    <updated>2022-12-27T04:25:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/2022-project-review"><![CDATA[<p>Reflections this year's hobby projects.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/2022-project-review"><![CDATA[
      
      <p>Here’s a review of all<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> the programming projects I worked on in my spare time this year.
I’m quite satisfied with the work I did. I learned a lot
and had some cool ideas that I will continue to build on. I’m glad I wrote this review, because
there’s some stuff in here that I’m quite proud of that I had forgotten about. This year was a
pretty long one for me.</p>
<h2 id="ipso"><a href="#ipso"><code>ipso</code></a></h2>
<p><em>Ongoing</em></p>
<p><a href="https://github.com/LightAndLight/ipso" class="uri">https://github.com/LightAndLight/ipso</a></p>
<p><code>ipso</code> is a scripting language that I started working on a bit over 2 years ago. My goal for this
project is to have a scripting language that I <em>actually enjoy</em> using. So far I haven’t found a
language that I find satisfactory for small administrative programs; Bash and Python have no types,
and Haskell is a bit slow and old for interpreted use, for example. <code>ipso</code> is my attempt at an answer.</p>
<p>This year I set up a website (<a href="https://ipso.dev" class="uri">https://ipso.dev</a>) and published my first few <a href="https://github.com/LightAndLight/ipso/releases">releases on
GitHub</a>.</p>
<p>Some of this year’s features and milestones that I’m proud of:</p>
<ul>
<li><a href="https://github.com/LightAndLight/ipso/issues/170">REPL</a></li>
<li><a href="https://github.com/LightAndLight/ipso/pull/177"><code>Debug</code> instances for extensible records and
variants</a> (<a href="https://ipso.dev/docs/reference.html#debugging">reference
docs</a>)</li>
<li><a href="https://github.com/LightAndLight/ipso/issues/95">Nested pattern matching</a></li>
<li><a href="https://github.com/LightAndLight/ipso/blob/main/.github/workflows/uploadToCache">Using <code>ipso</code> in a CI script</a></li>
</ul>
<p>The language itself is pretty stable now, so now my focus will be on writing standard library functions.</p>
<h2 id="ray-tracing-in-one-weekend"><a href="#ray-tracing-in-one-weekend"><code>ray-tracing-in-one-weekend</code></a></h2>
<p><em>January</em></p>
<p><a href="https://github.com/LightAndLight/ray-tracing-in-one-weekend" class="uri">https://github.com/LightAndLight/ray-tracing-in-one-weekend</a></p>
<p><img src="https://github.com/LightAndLight/ray-tracing-in-one-weekend/raw/main/render.png"
width="100%" ></p>
<p>An implementation of Peter Shirley’s <a href="https://raytracing.github.io/">Ray Tracing in One Weekend</a>
with some extra features. It was super fun. It’s incredibly satisfying to go from a bunch of math to
beautiful images.</p>
<p>The most striking thing I learned was <a href="https://en.wikipedia.org/wiki/Monte_Carlo_integration">Monte Carlo
integration</a>. It’s a way to compute integrals
using random numbers. Ray tracing uses it to approximate the colour of a point on a surface. Every
point on a surface has a specific, well-defined colour, and that colour can be the result of
contributions from an extremely large number incident rays. The point’s colour can be expressed as
an integral, and we use Monte Carlo integration to compute the integral with a varying level of
accuracy. For a preview render, we can use few samples, and quickly produce a noisy image. For a full
render we can use many samples, which will take longer, but will give a very accurate result.</p>
<h2 id="sylva"><a href="#sylva"><code>sylva</code></a></h2>
<p><em>January</em></p>
<p><a href="https://github.com/LightAndLight/sylva" class="uri">https://github.com/LightAndLight/sylva</a></p>
<p>“Sylva” means “forest” in Latin (according to Google Translate). I was playing with some
ideas about wikis / “document-based knowledge graphs”.</p>
<p>There were tree things I wanted to combine:</p>
<ul>
<li>A web-based user interface</li>
<li>Using a Git repository for versioning documents</li>
<li>Preventing dead links within the “wiki”</li>
</ul>
<p>This was just a sketch and I don’t plan to do anything with it.</p>
<h2 id="editor-vue"><a href="#editor-vue"><code>editor-vue</code></a></h2>
<p><em>March</em></p>
<p><a href="https://github.com/LightAndLight/editor-vue" class="uri">https://github.com/LightAndLight/editor-vue</a></p>
<p>A while ago I built a toy <a href="https://github.com/LightAndLight/edit-log">structural code editor</a> using
Haskell (GHCJS), and the <code>reflex</code> FRP library. I wasn’t happy with the performance. I heard about
<a href="https://vuejs.org/">vue.js</a> and was curious what it would be like to use it instead of <code>reflex</code>. I
rebuilt some of the code editor using <code>vue.js</code> with TypeScript, enough to get a sense of the coding
style and performance of the app. I was impressed by the performance improvements, and found
TypeScript tolerable (and much, much better than plain JavaScript).</p>
<h2 id="nix-docs"><a href="#nix-docs"><code>nix-docs</code></a></h2>
<p><em>March / April</em></p>
<p><a href="https://github.com/LightAndLight/nix-docs" class="uri">https://github.com/LightAndLight/nix-docs</a></p>
<p><code>nix-docs</code> is an ongoing experiment with reference documentation for some important Nix functions. Most Nix documentation is prose paragraphs, which is pretty bad for reference docs. Reference docs
need to be skimmable, terse, and interlinked. Here’s the <code>nix-docs</code> page for
<code>mkDerivation</code>: <a href="https://blog.ielliott.io/nix-docs/mkDerivation.html" class="uri">https://blog.ielliott.io/nix-docs/mkDerivation.html</a>.</p>
<p>This year I updated the styling to match the new <a href="https://nixos.org/">NixOS</a> design and wrote a documentation generator for the content (my first iteration was hand-edited HTML that I copied
from the Nixpkgs manual).</p>
<h2 id="ccc"><a href="#ccc"><code>ccc</code></a></h2>
<p><em>May</em></p>
<p><a href="https://github.com/LightAndLight/ccc" class="uri">https://github.com/LightAndLight/ccc</a></p>
<p><code>ccc</code> stands for <a href="https://ncatlab.org/nlab/show/cartesian+closed+category">cartesian closed
category</a>. I was inspired by <a href="https://www.typetheoryforall.com/2022/05/09/17-The-Lost-Elegance-of-Computation-(Conal-Elliott).html">this podcast with Conal
Elliott</a>,
and revisited his <a href="http://conal.net/papers/compiling-to-categories/">compiling to categories</a> and
<a href="http://conal.net/papers/calculating-compilers-categorically/">calculating compilers categorically</a>
papers. One important insight from “calculating compilers categorically” is that translating lambda
expressions into CCC syntax sort of “sequentialises” them. The composition operation in a category
implies an order of operations: <code>g ∘ f</code> is often read as <code>g</code> after <code>f</code>. It seems to me that CCC
syntax is closer to our <a href="https://doi.org/10.1145/359576.359579">word-at-a-time</a>-style imperative CPUs.</p>
<p>This leads to the first idea I explored in <code>ccc</code> was: using CCC syntax as an intermediate
representation for lambda calculus. This worked out really well; I learned that the lambda to CCC
translation also performs closure conversion, which is another reason that CCC syntax is easier to
compile to imperative code.</p>
<p>The second idea builds on the first. Once we have a program in CCC syntax, a compiler can be defined
as a functor from CCC syntax to another cartesian closed category. I think Conal mentioned this in
the podcast episode. I wrote a messy <a href="https://github.com/LightAndLight/ccc/blob/68d0214a778a19f04ee7c96a973749bd0d09d4d1/src/SSA.hs">SSA
compiler</a>
as a functor from CCC syntax arrows to “SSA builder arrows” (Haskell functions of type
<code>SSA -&gt; SSA</code>). It was pretty straightforward because CCC syntax is sequential and closure-converted.</p>
<p>The last idea was to apply these techniques to
<a href="https://en.wikipedia.org/wiki/Substructural_logic">substructural</a> lambda calculi (i.e. <a href="https://en.wikipedia.org/wiki/Affine_logic">affine</a> and
<a href="https://en.wikipedia.org/wiki/Linear_logic">linear</a> lambda calculus). Linear lambda calculus has
its own categorical syntax (<a href="https://ncatlab.org/nlab/show/symmetric+monoidal+category">closed symmetric monoidal
category</a> - call it CSMC for short),
so I wrote a
<a href="https://github.com/LightAndLight/ccc/blob/68d0214a778a19f04ee7c96a973749bd0d09d4d1/proofs/Linear.agda">program</a>
that translates lambda calculus to CSMC syntax, and rejects lambda calculus terms that have
non-linear variable usages. I then used the same program structure to translate lambda terms to
<a href="https://ncatlab.org/nlab/show/semicartesian+monoidal+category">semicartesian monoidal category</a>
syntax, which is just CSMC syntax with a <a href="https://ncatlab.org/nlab/show/terminal+object">terminal
object</a>.
<a href="https://github.com/LightAndLight/ccc/blob/68d0214a778a19f04ee7c96a973749bd0d09d4d1/proofs/Affine.agda">That translation</a>
allows unused variables while rejecting variable duplication, which makes it affine. The <a href="https://github.com/LightAndLight/ccc/blob/68d0214a778a19f04ee7c96a973749bd0d09d4d1/proofs/Unrestricted.agda">final
translation</a>
adds a <code>dup : a -&gt; a ⊗ a</code> arrow to the semicartesian monoidal category, which gets us back to a
cartesian closed category (but with a slightly different syntax) and unrestricted lambda calculus.</p>
<p>This journey lead to a style for checking lambda calculus that works for linear, affine,
and unrestricted lambda calculus. I think would be interesting to create a type checker that checks
in this style. My intuition says such a type checker might be easier to parallelise.</p>
<p>I also noticed that the <a href="https://github.com/LightAndLight/ccc/blob/68d0214a778a19f04ee7c96a973749bd0d09d4d1/proofs/Unrestricted.agda#L35-L49">CCC
syntax</a>
I settled on is explicit about parallel computations. While composition (<code>f ∘ g</code>) can be thought of as <code>f</code> after
<code>g</code>, the tensor operator (<code>f ⊗ g</code>) can be thought of as <code>f</code> and <code>g</code> in parallel. There’s a sense in
which this CCC syntax “reveals” parallelism that’s inherient in the lambda calculus. I’m curious
what it would be like to write a multi-core parallel evaluator based on this.</p>
<h2 id="march"><a href="#march"><code>march</code></a></h2>
<p><em>June</em></p>
<p><a href="https://github.com/LightAndLight/march" class="uri">https://github.com/LightAndLight/march</a></p>
<p>I wanted to check for broken local links markdown documents, and create
a “move” command that works like <code>mv</code> but also renames links. I finished the former but not the latter.</p>
<h2 id="bidirectional-typechecking-with-unification"><a href="#bidirectional-typechecking-with-unification"><code>bidirectional-typechecking-with-unification</code></a></h2>
<p><em>June</em></p>
<p><a href="https://github.com/LightAndLight/bidirectional-typechecking-with-unification" class="uri">https://github.com/LightAndLight/bidirectional-typechecking-with-unification</a></p>
<p>This work was inspired by <a href="https://www.haskellforall.com/2022/06/the-appeal-of-bidirectional-type.html">an article about the limitations of unification-based type
checking</a>. It seemed to
claim that <a href="https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system">Hindley-Milner</a> / unification-based type checking is very limited, and presented a
dichotomy between bidirectional typing and unification that I don’t agree with.</p>
<p>I wrote a Hindley-Milner-based type checker for a language with subtyping by applying bidirectional
principles. It has higher-rank polymorphism, existential types, optional record fields, and default
record fields, which are all powered by the same subtyping mechanism. Unification and instantiation
are also performed by the subtyping mechanism.</p>
<p>The key insight is to allow the subtyping check to transform terms. A type <code>A</code> is a subtype of <code>B</code>
when values of type <code>A</code> can be used where values of type <code>B</code> are expected. This is often written as
<code>A :&gt; B</code>, and in code as something like <code>isSubtypeOf : Type -&gt; Type -&gt; Bool</code>. My type checker
returns evidence that the subtyping relation holds, which could be written as
<code>(a : A) :&gt; B  ~&gt; b</code>, and as a function: <code>isSubtypeOf : (Expr, Type) -&gt; Type -&gt; Maybe Expr</code>. The
bidirectional style means ensures that “checking” types drives subtyping. This is
all perfectly compatible with unification-based inference.</p>
<p>This deserves a much clearer explanation in its own blog post. I think it’s a promising result
for programming language design.</p>
<h2 id="little"><a href="#little"><code>little</code></a></h2>
<p><em>June / July</em></p>
<p><a href="https://github.com/LightAndLight/little" class="uri">https://github.com/LightAndLight/little</a></p>
<p><code>little</code> is my first attempt at a <a href="https://doi.org/10.1093/comjnl/27.2.97">Knuth-style literate
programming</a> system. I want to write documents about code
that are also the source truth for the code. Systems like <a href="https://www.haskell.org/onlinereport/literate.html">literate Haskell</a> are unsatisfying
to me because I have to present the code to the reader in the same order that the code appears
in the source file. For example, all literate Haskell articles will begin with a preamble of imports
(<a href="https://blog.ielliott.io/continuations-from-the-ground-up/">example article</a>). I want to present
code to the reader in a non-linear fashion, in a way that supports my explanation. I imagine that
I’d often put import declarations in an appendix, for instance.</p>
<p><code>little doc</code> generates a document that I can publish on
the web, and <code>little code</code> generates the codebase that is described in the document. Another fun use
case is “self-documenting shell scripts”
(<a href="https://github.com/LightAndLight/little/blob/main/examples/script.lit">example</a>). Rather than
commenting a bash script, you can write a literate document that describes a bash script, and give
the document a shebang line.</p>
<p><code>little</code> uses XML for its markup, so that I can use whatever “presentation” markup I want (Markdown,
LaTex, HTML, etc.). I was surprised by how “not terrible” it felt to use XML for this. I have a
strong bias against XML in general, and now that bias has gained some nuance. XML feels alright for
<em>markup</em>, that is, for extra information in documents that are mostly text which
people will consume by reading. That’s what it was designed for; it’s the eXtensible <em>Markup</em>
Language. What I now object to is the use of XML as a data format.
<a href="https://www.devever.net/~hl/xml">This article</a> has a good heuristic for distinguishing the two uses: if
you remove all the tags from your XML document, will it still make sense to a reader? I’ve tried to
apply this heuristic to the syntax of <code>little</code>.</p>
<p>The code is pretty crappy, so if I continued to work on this I’d rewrite it. I’m optimistic about
what I created so far, though.</p>
<h2 id="mininix"><a href="#mininix"><code>mininix</code></a></h2>
<p><em>August</em></p>
<p><a href="https://github.com/LightAndLight/mininix" class="uri">https://github.com/LightAndLight/mininix</a></p>
<p><code>mininix</code> is an attempt at understanding how Nix-style build systems work by writing a small one. It
includes a content-addressable store, a build database (using sqlite), a parallel build executor and a typed build language.</p>
<p>I also wanted to improve on the naming of concepts (i.e. use a better word than “derivation”), and
to keep typeability in mind from the start (Nix is very very untyped. Would types affect the build
system’s design?).</p>
<p>One idea I’d like to explore here is a sort of “local” version of Nix. Instead of having a global
store, have a per-project store for build artifacts similar to <code>cabal</code>’s <code>dist[-newstyle]</code>
directories and
<code>cargo</code>’s <code>target</code> directory.</p>
<p>I’m also interested in whether we can have build systems that reuse existing package declarations.
For example, if you want to use Nix to package a Haskell project, you need to convert your
<code>.cabal</code> file to a Nix expression (or do <a href="https://nixos.wiki/wiki/Import_From_Derivation">import from
derivation</a>, which I fundamentally disagree with).
What if there was a way to use the <code>.cabal</code> file without the grossness of import-from-derivation?</p>
<h2 id="top-down-hindley-milner"><a href="#top-down-hindley-milner"><code>top-down-hindley-milner</code></a></h2>
<p><em>September</em></p>
<p><a href="https://github.com/LightAndLight/top-down-hindley-milner" class="uri">https://github.com/LightAndLight/top-down-hindley-milner</a></p>
<p>This project shows a sort of “upside down” approach to Hindley-Milner type inference.
This work was inspired by some inaccurate type errors that <code>ipso</code> generated, and this algorithm is
my solution.</p>
<p><a href="https://ncatlab.org/nlab/show/bidirectional+typechecking">Bidirectional type
checking</a> separates inference from
checking, and this distinction is important in contrasting “normal” Hindley-Milner to the “top-down”
approach. Roughly speaking, Hindley-Milner constructs types through inference in a bottom-up
manner, and my algorithm refines types through checking from the top down.</p>
<p>In Hindley-Milner, all the work is done by inference and checking is the trivial case of
inference followed by unification with an expected type. In the “top-down” style, checking does all
the work, and inference is performed by checking against a fresh metavariable.</p>
<p>I want to combine this work with <a href="#bidirectional-typechecking-with-unification">the subtyping work</a> I mentioned earier.</p>
<h2 id="hover-pill"><a href="#hover-pill"><code>hover-pill</code></a></h2>
<p><em>October</em></p>
<p><a href="https://github.com/LightAndLight/hover-pill" class="uri">https://github.com/LightAndLight/hover-pill</a></p>
<p><code>hover-pill</code> is a game I created to learn the <a href="https://bevyengine.org/">Bevy</a> game engine. You can
try an early build <a href="https://blog.ielliott.io/hover-pill/">here</a>. It’s a 3D puzzle/platformer where
you fly around as a capsule-shaped object (I’m not a 3D artist) trying to reach the green goal square.</p>
<p>I haven’t done any game development for years, so this project was very refreshing. Once I had
all the mechanics working, I asked my girlfriend to test the levels I designed. Each time
she completed a level, I created a slightly more difficult one. She enjoyed playing it, and I’m glad that in the end I created
something fun.</p>
<p>Bevy uses <a href="https://wgpu.rs/"><code>wgpu</code></a> for graphics, which combined with Rusts awesome
cross-compilation support means it was pretty easy for me to develop on my desktop (with x86_64 and Vulkan), and
then compile a WASM and WebGL version for the web. It was a pleasant surprise, coming from Haskell
and GHCJS.</p>
<p>This was my first time using an
<a href="https://en.wikipedia.org/wiki/Entity_component_system">entity-component-system</a> framework, and I
enjoyed it. <a href="https://dataorienteddesign.com/dodbook/">Data-Oriented Design</a> helped me understand the
history behind the patterns. I think there are ideas here that apply outside of game development,
but I don’t know what they are yet. On example (and I think it’s where I learned about the DoD book)
is <a href="https://ziglang.org/download/0.8.0/release-notes.html#Reworked-Memory-Layout">this</a> explanation
of a “data-oriented” performance improvement in the Zig compiler.</p>
<h2 id="wgpu-mandelbrot"><a href="#wgpu-mandelbrot"><code>wgpu-mandelbrot</code></a></h2>
<p><em>October</em></p>
<p><a href="https://github.com/LightAndLight/wgpu-mandelbrot" class="uri">https://github.com/LightAndLight/wgpu-mandelbrot</a></p>
<p><img src="https://github.com/LightAndLight/wgpu-mandelbrot/raw/main/images/screenshot-2.png"
width="100%" /></p>
<p>After <a href="#hover-pill">hover-pill</a> I wanted to learn more about graphics APIs and GPU programming. I realised that computing the mandelbrot set was an
“embarrassingly parallel” problem, so it would be a good fit for GPU programming.</p>
<p>The mandelbrot renderer runs in realtime. It has a satisfying “blooming” effect as the iteration
count ticks up and more points are coloured. The mandelbrot
calculations are performed in a compute shader, and the colours are assigned using a
<a href="https://en.wikipedia.org/wiki/Plotting_algorithms_for_the_Mandelbrot_set#Histogram_coloring">histogram algorithm</a>
on the CPU. I couldn’t figure out how to do histogram colouring on the GPU.</p>
<p>To make sense of the WebGPU API, I created this diagram which displays all relevant (Web)GPU
resources and their relationships:</p>
<iframe style="border: 1px solid rgba(0, 0, 0, 0.1);" width="800" height="450" src="https://www.figma.com/embed?embed_host=share&amp;url=https%3A%2F%2Fwww.figma.com%2Ffile%2FIr3gsGIELdVBwYgVkCiHvE%2Fwebgpu%3Fnode-id%3D0%253A1%26t%3DUIEhGQEzO3ObVrhi-1" allowfullscreen>
</iframe>
<p>I have a much better sense of GPU programming fundamentals, and I think the careful design of WebGPU helped.
It’s higher level than Vulkan, but more explicit than OpenGL. I’ve done a Vulkan tutorial and forgot
almost all of it. Having learned the fundamentals <code>wgpu</code>, I think the Vulkan API would make a lot more sense
to me now.</p>
<h2 id="hedge"><a href="#hedge"><code>hedge</code></a></h2>
<p><em>December</em></p>
<p><a href="https://github.com/LightAndLight/hedge" class="uri">https://github.com/LightAndLight/hedge</a></p>
<p><code>hedge</code> is a library that makes it easier for me to write web information systems with Haskell. I’ve
been developing a sense of style and a set of patterns around writing Haskell web apps,
in particular
using <a href="https://hackage.haskell.org/package/servant">servant</a> and focusing on server-side rendered resources, and <code>hedge</code> is
kind of my “kitchen sink” for things that support the style.</p>
<p>I might create a command-line program for setting up a new project, adding endpoints, and other
forms of boilerplate I find.</p>
<p>I’m not sure if it will ever lead to something I could call a “framework”, like
<a href="https://rubyonrails.org/">Rails</a>. Right now I have the sense that it would be more like a <a href="https://en.wikipedia.org/wiki/A_Pattern_Language">pattern
language</a> with automated helpers.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>that made it onto GitHub<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
    ]]></content>
    
</entry>
<entry>
    <title>RIP Dream.In.Code</title>
    <link href="https://blog.ielliott.io/rip-dreamincode" />
    
    <id>https://blog.ielliott.io/rip-dreamincode</id>
    
    <published>2022-07-06T00:00:00Z</published>
    <updated>2022-07-06T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/rip-dreamincode"><![CDATA[<p><a href="https://web.archive.org/web/20220105235917/https://www.dreamincode.net/">Dream.In.Code</a> was a
programming help forum that ran from 2001 to the beginning of 2022. It was recently <a href="https://web.archive.org/web/20220116161045/https://www.dreamincode.net/forums/topic/421898-dreamincode-shutting-down/">shut
down</a>
due to hosting costs. My participation in Dream.In.Code, starting from 2009 and ending somewhere in
2013, represents the beginning of my life as a programmer. Over the past 10 or so years, programming
has become a <em>huge</em> part of my life. I’d like to acknowledge the role this forum played in my development.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/rip-dreamincode"><![CDATA[
      
      <p><a href="https://web.archive.org/web/20220105235917/https://www.dreamincode.net/">Dream.In.Code</a> was a
programming help forum that ran from 2001 to the beginning of 2022. It was recently <a href="https://web.archive.org/web/20220116161045/https://www.dreamincode.net/forums/topic/421898-dreamincode-shutting-down/">shut
down</a>
due to hosting costs. My participation in Dream.In.Code, starting from 2009 and ending somewhere in
2013, represents the beginning of my life as a programmer. Over the past 10 or so years, programming
has become a <em>huge</em> part of my life. I’d like to acknowledge the role this forum played in my development.</p>
<p>Dream.In.Code has been thoroughly archived on web.archive.org, so I scraped
the archives for my old posts. I was quite surprised by what I found.</p>
<p>I had forgotten how much of a beginner I was when I started posting there.
My initial posts
were variations of “I wrote this code and it doesn’t work and I don’t know why. Help?”
I could barely ask a coherent question.
Later, my questions became more targeted, like “How do I update all the items in an array?”
It was sobering to be reminded of a time when I didn’t know what a <code>for</code> loop was, and didn’t really
know how to figure it out for myself.</p>
<p>What left an even stronger impression was the quality of answers I recieved. Every question I asked
recieved patient, respectful responses. No one complained about my writing style (I was 13 at the time, and re-reading
these posts caused some eye-rolls). No one berated me when I left out helpful debugging information
like log files or compiler errors. No one made me feel bad for asking
questions. I think this was the best possible start I could have asked for. I’m not sure where
someone would go in 2022 for the same experience. Probably not Reddit or StackOverflow.</p>
<p>When I was learning to code, I had no one to turn to “in real life”. Posting a code snippet to a
forum and asking, “pls halp” was all I could do. The members of Dream.In.Code turned that into a
positive, constructive experience.</p>
<p>Thanks, Dream.In.Code</p>
    ]]></content>
    
</entry>
<entry>
    <title>WebGL Slower Than Canvas?</title>
    <link href="https://blog.ielliott.io/webgl-slower-than-canvas" />
    
    <id>https://blog.ielliott.io/webgl-slower-than-canvas</id>
    
    <published>2021-05-20T00:00:00Z</published>
    <updated>2021-05-20T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/webgl-slower-than-canvas"><![CDATA[<p>I’ve recently been working on <a href="https://github.com/LightAndLight/rust-wasm-gol/">web a graphics project</a>
where I played a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">Canvas API</a> implementation
against a <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API">WebGL</a> implementation. When running the app in Firefox on Linux, I was surprised to find that the WebGL version was 10-30% <em>slower</em>
(in frames per second) than the Canvas version.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/webgl-slower-than-canvas"><![CDATA[
      
      <p>I’ve recently been working on <a href="https://github.com/LightAndLight/rust-wasm-gol/">web a graphics project</a>
where I played a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">Canvas API</a> implementation
against a <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API">WebGL</a> implementation. When running the app in Firefox on Linux, I was surprised to find that the WebGL version was 10-30% <em>slower</em>
(in frames per second) than the Canvas version.</p>
<p>After much searching I was able to diagnose and fix the problem, which came
down to graphics drivers and browser rendering settings. If your problem is
similar to mine, here’s how you might be able to solve it:</p>
<ol type="1">
<li><p>Check GPU driver status in the browser.</p>
<p>In Firefox, navigate to <code>about:support</code>. <code>Ctrl+F Graphics</code>. Look at the <code>WebGL 1 Driver {Renderer,Version}</code>
rows. If you don’t see your GPU manufacturer and model in these rows, then you need to install
the correct drivers.</p>
<p>For reference, I’m running a Nvidia GeForce RTX2070. Without drivers, my driver renderer was <code>VMware, Inc. -- llvmpipe (LLVM 9.0.1, 256 bits)</code>
and my driver version was <code>3.1 Mesa 20.1.10</code>.</p></li>
<li><p>Install GPU drivers.</p>
<p>I’m on NixOS, so this was as simple as adding</p>
<pre><code>nixpkgs.config.allowUnfree = true;
services.xserver.videoDrivers = [ &quot;nvidia&quot; ];</code></pre>
<p>to my <code>configuration.nix</code>, then running <code>sudo nixos-rebuild switch &amp;&amp; reboot</code>.</p></li>
<li><p>Confirm driver installation.</p>
<p>Repeat step 1. If you still can’t see your GPU manufacturer and model, then I can’t help you.</p>
<p>After step 2, my driver renderer was <code>NVIDIA Corporation -- GeForce RTX 2070/PCIe/SSE2</code> and driver version was
<code>4.6.0 NVIDIA 455.38</code>.</p></li>
<li><p>Enable <a href="https://hacks.mozilla.org/2017/10/the-whole-web-at-maximum-fps-how-webrender-gets-rid-of-jank/">WebRender</a>.</p>
<p>In the Graphics section of <code>about:support</code>, check the <code>Compositing</code> row. If it says <code>WebRender</code>, then you’re
done. If it says <code>Basic</code>, then you need to enable WebRender.</p>
<p>Navigate to <code>about:config</code>, move past the warning, and search for <code>gfx.webrender.enabled</code>. Set it to <code>true</code> and
restart Firefox. Confirm this change by checking <code>Compositing</code> row in <code>about:support</code>.</p></li>
</ol>
<p>Before, each <a href="https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame</a> call
lasted 14-15ms in my Canvas implementation, but the app was running well below 60fps. Each frame lasted ~10ms in my WebGL implementation,
but the framerate was even worse than the Canvas version!</p>
<p>After following these instructions, both my Canvas implementation and WebGL implementation run at 60fps. Canvas’ frame
duration didn’t appear to change, but WebGL’s frame duration dropped to ~4ms. Yay!</p>
    ]]></content>
    
</entry>
<entry>
    <title>An Example of Defunctionalisation in Rust</title>
    <link href="https://blog.ielliott.io/rust-defun-example" />
    
    <id>https://blog.ielliott.io/rust-defun-example</id>
    
    <published>2021-02-06T00:00:00Z</published>
    <updated>2021-02-06T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/rust-defun-example"><![CDATA[<p>I’m an experienced Haskell programmer, and I’ve been writing a lot of Rust lately.
I recently ran into a little trouble when porting a simple function from Haskell to
Rust. This article is a short description of my journey.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/rust-defun-example"><![CDATA[
      
      <p>I’m an experienced Haskell programmer, and I’ve been writing a lot of Rust lately.
I recently ran into a little trouble when porting a simple function from Haskell to
Rust. This article is a short description of my journey.</p>
<hr />
<p><a href="https://en.wikipedia.org/wiki/De_Bruijn_index">De Bruijn indexed</a> terms are
<a href="https://en.wikipedia.org/wiki/Functor">functorial</a> in their free variables.
This means that given a datatype <code>Expr</code>, we can write a function
<code>map_freevars : (Int -&gt; Int) -&gt; Expr -&gt; Expr</code> such that <code>map_freevars id == id</code>
and <code>map_freevars f ∘ map_freevars g == map_freevars (f ∘ g)</code>. In Haskell, I’d
implement this as follows:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Expr</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">Var</span> <span class="dt">Int</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">App</span> <span class="dt">Expr</span> <span class="dt">Expr</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Lam</span> <span class="dt">Expr</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="ot">map_freevars ::</span> (<span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span>) <span class="ot">-&gt;</span> <span class="dt">Expr</span> <span class="ot">-&gt;</span> <span class="dt">Expr</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>map_freevars f e <span class="ot">=</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">case</span> e <span class="kw">of</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Var</span> n <span class="ot">-&gt;</span> <span class="dt">Var</span> (f n)</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>    <span class="dt">App</span> a b <span class="ot">-&gt;</span> <span class="dt">App</span> (map_freevars f a) (map_freevars f b)</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Lam</span> b <span class="ot">-&gt;</span> <span class="dt">Lam</span> (map_freevars (\n <span class="ot">-&gt;</span> <span class="kw">if</span> n <span class="op">==</span> <span class="dv">0</span> <span class="kw">then</span> <span class="dv">0</span> <span class="kw">else</span> <span class="dv">1</span> <span class="op">+</span> f (n <span class="op">-</span> <span class="dv">1</span>)) b)</span></code></pre></div>
<p>Now, here’s a direct translation from Haskell to Rust:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> Expr <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    Var(<span class="dt">usize</span>)<span class="op">,</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    App(<span class="dt">Box</span><span class="op">&lt;</span>Expr<span class="op">&gt;,</span> <span class="dt">Box</span><span class="op">&lt;</span>Expr<span class="op">&gt;</span>)<span class="op">,</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    Lam(<span class="dt">Box</span><span class="op">&lt;</span>Expr<span class="op">&gt;</span>)<span class="op">,</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> map_freevars<span class="op">&lt;</span>F<span class="op">:</span> <span class="bu">Fn</span>(<span class="dt">usize</span>) <span class="op">-&gt;</span> <span class="dt">usize</span><span class="op">&gt;</span>(f<span class="op">:</span> F<span class="op">,</span> e<span class="op">:</span> <span class="op">&amp;</span>Expr) <span class="op">-&gt;</span> Expr <span class="op">{</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">match</span> e <span class="op">{</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>        <span class="pp">Expr::</span>Var(n) <span class="op">=&gt;</span> <span class="pp">Expr::</span>Var(f(<span class="op">*</span>n))<span class="op">,</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>        <span class="pp">Expr::</span>App(a<span class="op">,</span> b) <span class="op">=&gt;</span> <span class="pp">Expr::</span>App(<span class="dt">Box</span><span class="pp">::</span>new(map_freevars(f<span class="op">,</span> a))<span class="op">,</span> <span class="dt">Box</span><span class="pp">::</span>new(map_freevars(f<span class="op">,</span> b)))<span class="op">,</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>        <span class="pp">Expr::</span>Lam(b) <span class="op">=&gt;</span> <span class="pp">Expr::</span>Lam(<span class="dt">Box</span><span class="pp">::</span>new(map_freevars(</span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>            <span class="op">|</span>n<span class="op">|</span> <span class="op">{</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>                <span class="cf">if</span> n <span class="op">==</span> <span class="dv">0</span> <span class="op">{</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>                    <span class="dv">0</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>                <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a>                    <span class="dv">1</span> <span class="op">+</span> f(n <span class="op">-</span> <span class="dv">1</span>)</span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>                <span class="op">}</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>            <span class="op">},</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>            b</span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>        )))<span class="op">,</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>This doesn’t typecheck because the call to <code>map_freevars(f, a)</code> takes ownership of <code>f</code>,
which means <code>f</code> can no longer be used in the call to <code>map_freevars(f, b)</code>.</p>
<p>To avoid this, <code>map_freevars</code> should <em>borrow</em> the mapping function:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> map_freevars<span class="op">&lt;</span>F<span class="op">:</span> <span class="bu">Fn</span>(<span class="dt">usize</span>) <span class="op">-&gt;</span> <span class="dt">usize</span><span class="op">&gt;</span>(f<span class="op">:</span> <span class="op">&amp;</span>F<span class="op">,</span> e<span class="op">:</span> <span class="op">&amp;</span>Expr) <span class="op">-&gt;</span> Expr <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    <span class="cf">match</span> e <span class="op">{</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>        <span class="pp">Expr::</span>Var(n) <span class="op">=&gt;</span> <span class="pp">Expr::</span>Var(f(<span class="op">*</span>n))<span class="op">,</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>        <span class="pp">Expr::</span>App(a<span class="op">,</span> b) <span class="op">=&gt;</span> <span class="pp">Expr::</span>App(<span class="dt">Box</span><span class="pp">::</span>new(map_freevars(f<span class="op">,</span> a))<span class="op">,</span> <span class="dt">Box</span><span class="pp">::</span>new(map_freevars(f<span class="op">,</span> b)))<span class="op">,</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>        <span class="pp">Expr::</span>Lam(b) <span class="op">=&gt;</span> <span class="pp">Expr::</span>Lam(<span class="dt">Box</span><span class="pp">::</span>new(map_freevars(</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>            <span class="op">&amp;|</span>n<span class="op">|</span> <span class="op">{</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>                <span class="cf">if</span> n <span class="op">==</span> <span class="dv">0</span> <span class="op">{</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>                    <span class="dv">0</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>                <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>                    <span class="dv">1</span> <span class="op">+</span> f(n <span class="op">-</span> <span class="dv">1</span>)</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>                <span class="op">}</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>            <span class="op">},</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>            b</span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>        )))<span class="op">,</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>But this doesn’t compile either! The Rust compiler reports
that it <code>reached the recursion limit while instantiating map_freevars::&lt;[closure@...]&gt;</code>.
Rust generates all its closures at compile time, and this code causes the compiler to
generate a countably infinite number of closures.</p>
<p>For every known closure that is passed to <code>map_freevars</code> as <code>f</code>, Rust generates another
closure for <code>|n| if n == 0 { 0 } else { 1 + f(n - 1) } }</code>. But <code>|n| if n == 0 { 0 } else { 1 + f(n - 1) } }</code>
is also passed to <code>map_freevars</code>, so another closure needs to be generated. And <em>that</em> closure is
also passed to <code>map_freevars</code>, so another closure needs to be generated. And so on.</p>
<p>The next natural step is to use a <a href="https://doc.rust-lang.org/book/ch17-02-trait-objects.html">trait object</a>.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> map_freevars(f<span class="op">:</span> <span class="op">&amp;</span><span class="kw">dyn</span> <span class="bu">Fn</span>(<span class="dt">usize</span>) <span class="op">-&gt;</span> <span class="dt">usize</span><span class="op">,</span> e<span class="op">:</span> <span class="op">&amp;</span>Expr) <span class="op">-&gt;</span> Expr <span class="op">{</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="cf">match</span> e <span class="op">{</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>        <span class="pp">Expr::</span>Var(n) <span class="op">=&gt;</span> <span class="pp">Expr::</span>Var(f(<span class="op">*</span>n))<span class="op">,</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>        <span class="pp">Expr::</span>App(a<span class="op">,</span> b) <span class="op">=&gt;</span> <span class="pp">Expr::</span>App(<span class="dt">Box</span><span class="pp">::</span>new(map_freevars(f<span class="op">,</span> a))<span class="op">,</span> <span class="dt">Box</span><span class="pp">::</span>new(map_freevars(f<span class="op">,</span> b)))<span class="op">,</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>        <span class="pp">Expr::</span>Lam(b) <span class="op">=&gt;</span> <span class="pp">Expr::</span>Lam(<span class="dt">Box</span><span class="pp">::</span>new(map_freevars(</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>            <span class="op">&amp;|</span>n<span class="op">|</span> <span class="op">{</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>                <span class="cf">if</span> n <span class="op">==</span> <span class="dv">0</span> <span class="op">{</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>                    <span class="dv">0</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>                <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>                    <span class="dv">1</span> <span class="op">+</span> f(n <span class="op">-</span> <span class="dv">1</span>)</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>                <span class="op">}</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>            <span class="op">},</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>            b</span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>        )))<span class="op">,</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>A <code>&amp;dyn</code> reference is a pair of pointers; one pointer to a value of a type that implements the trait,
and another pointer to the implementation of the trait for that type<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>.</p>
<p>This code is perfectly usable, and I’d guess it’s the ‘idiomatic’ Rust solution. But there’s one final
step I’d like to take, mostly for educational perposes, and for a small efficiency gain.</p>
<p>For all intents and purposes, there are only two possible ‘origins’ for <code>f</code>:</p>
<ol type="1">
<li>It was passed to <code>map_freevars</code> unchanged, either from a top-level call or from a recursive call at an
<code>App</code> node</li>
<li>It was wrapped in a closure before being passed to <code>map_freevars</code> at a <code>Lam</code> node</li>
</ol>
<p>This structure is described by the following datatype:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> Origin<span class="op">&lt;</span><span class="ot">&#39;a</span><span class="op">,</span> F<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>    Unchanged(F)<span class="op">,</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    LamNode(<span class="op">&amp;</span><span class="ot">&#39;a</span> Origin<span class="op">&lt;</span><span class="ot">&#39;a</span><span class="op">,</span> F<span class="op">&gt;</span>)</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The <code>Origin</code> datatype can be interpreted as a function from <code>usize</code> to <code>usize</code>:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span> <span class="op">&lt;</span><span class="ot">&#39;a</span><span class="op">,</span> F<span class="op">:</span> <span class="bu">Fn</span>(<span class="dt">usize</span>) <span class="op">-&gt;</span> <span class="dt">usize</span><span class="op">&gt;</span> Origin<span class="op">&lt;</span><span class="ot">&#39;a</span><span class="op">,</span> F<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> apply(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> n<span class="op">:</span> <span class="dt">usize</span>) <span class="op">-&gt;</span> <span class="dt">usize</span> <span class="op">{</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>        <span class="cf">match</span> <span class="kw">self</span> <span class="op">{</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>            <span class="pp">Origin::</span>Unchanged(f) <span class="op">=&gt;</span> f(n)<span class="op">,</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>            <span class="pp">Origin::</span>LamNode(f) <span class="op">=&gt;</span> <span class="cf">if</span> n <span class="op">==</span> <span class="dv">0</span> <span class="op">{</span> <span class="dv">0</span> <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span> <span class="dv">1</span> <span class="op">+</span> f<span class="op">.</span>apply(n<span class="op">-</span><span class="dv">1</span>) <span class="op">}</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><em>Challenge: implement <code>Origin::apply</code> using constant stack space.</em></p>
<p>Now the <code>Origin::LamNode</code> constructor replaces the fresh closure in the <code>Lam</code> branch:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> map_freevars<span class="op">&lt;</span><span class="ot">&#39;a</span><span class="op">,</span> F<span class="op">:</span> <span class="bu">Fn</span>(<span class="dt">usize</span>) <span class="op">-&gt;</span> <span class="dt">usize</span><span class="op">&gt;</span>(f<span class="op">:</span> <span class="op">&amp;</span><span class="ot">&#39;a</span> Origin<span class="op">&lt;</span><span class="ot">&#39;a</span><span class="op">,</span> F<span class="op">&gt;,</span> e<span class="op">:</span> <span class="op">&amp;</span>Expr) <span class="op">-&gt;</span> Expr <span class="op">{</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>    <span class="cf">match</span> e <span class="op">{</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>        <span class="pp">Expr::</span>Var(n) <span class="op">=&gt;</span> <span class="pp">Expr::</span>Var(f<span class="op">.</span>apply(<span class="op">*</span>n))<span class="op">,</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>        <span class="pp">Expr::</span>App(a<span class="op">,</span> b) <span class="op">=&gt;</span> <span class="pp">Expr::</span>App(<span class="dt">Box</span><span class="pp">::</span>new(map_freevars(f<span class="op">,</span> a))<span class="op">,</span> <span class="dt">Box</span><span class="pp">::</span>new(map_freevars(f<span class="op">,</span> b)))<span class="op">,</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>        <span class="pp">Expr::</span>Lam(b) <span class="op">=&gt;</span> <span class="pp">Expr::</span>Lam(<span class="dt">Box</span><span class="pp">::</span>new(map_freevars(<span class="op">&amp;</span><span class="pp">Origin::</span>LamNode(f))))<span class="op">,</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>This transformation is an example of <a href="https://en.wikipedia.org/wiki/Defunctionalization">defunctionalisation</a>.</p>
<p>Here, the practical benefit is that <code>&amp;Origin</code> is half the size of a <code>&amp;dyn Fn(usize) -&gt; usize</code> (a single pointer
instead of two), so recursing over a <code>Lam</code> node uses less stack space.</p>
<p>The interface to <code>map_freevars</code> can then be cleaned up using the worker/wrapper pattern:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> map_freevars<span class="op">&lt;</span>F<span class="op">:</span> <span class="bu">Fn</span>(<span class="dt">usize</span>) <span class="op">-&gt;</span> <span class="dt">usize</span><span class="op">&gt;</span>(f<span class="op">:</span> F<span class="op">,</span> e<span class="op">:</span> <span class="op">&amp;</span>Expr) <span class="op">-&gt;</span> Expr <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">fn</span> go<span class="op">&lt;</span><span class="ot">&#39;a</span><span class="op">,</span> F<span class="op">:</span> <span class="bu">Fn</span>(<span class="dt">usize</span>) <span class="op">-&gt;</span> <span class="dt">usize</span><span class="op">&gt;</span>(f<span class="op">:</span> <span class="op">&amp;</span><span class="ot">&#39;a</span> Origin<span class="op">&lt;</span><span class="ot">&#39;a</span><span class="op">,</span> F<span class="op">&gt;,</span> e<span class="op">:</span> <span class="op">&amp;</span>Expr) <span class="op">-&gt;</span> Expr <span class="op">{</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>        <span class="cf">match</span> e <span class="op">{</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>            <span class="pp">Expr::</span>Var(n) <span class="op">=&gt;</span> <span class="pp">Expr::</span>Var(f<span class="op">.</span>apply(<span class="op">*</span>n))<span class="op">,</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>            <span class="pp">Expr::</span>App(a<span class="op">,</span> b) <span class="op">=&gt;</span> <span class="pp">Expr::</span>App(<span class="dt">Box</span><span class="pp">::</span>new(go(f<span class="op">,</span> a))<span class="op">,</span> <span class="dt">Box</span><span class="pp">::</span>new(go(f<span class="op">,</span> b)))<span class="op">,</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>            <span class="pp">Expr::</span>Lam(b) <span class="op">=&gt;</span> <span class="pp">Expr::</span>Lam(<span class="dt">Box</span><span class="pp">::</span>new(go(<span class="op">&amp;</span><span class="pp">Origin::</span>LamNode(f))))<span class="op">,</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>    go(<span class="op">&amp;</span><span class="pp">Origin::</span>Unchanged(f)<span class="op">,</span> e)</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<hr />
<p>I haven’t benchmarked the defunctionalised approach and compared it against the trait object
implementation. If anyone has suggestions for easily measuring the time and memory usage of
Rust programs, preferably by function, then please let me know.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>This is a form of existential quantification. The Haskell equivalent looks something like
<code>data Some (c :: Constraint) where; Some :: c a =&gt; a -&gt; Some c</code><a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
    ]]></content>
    
</entry>
<entry>
    <title>Docker Cleanup Commands</title>
    <link href="https://blog.ielliott.io/docker-cleanup-commands" />
    
    <id>https://blog.ielliott.io/docker-cleanup-commands</id>
    
    <published>2020-11-07T00:00:00Z</published>
    <updated>2020-11-07T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/docker-cleanup-commands"><![CDATA[<p>I’ve Googled this one too many times, so I’m writing it here for future reference.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/docker-cleanup-commands"><![CDATA[
      
      <p>I’ve Googled this one too many times, so I’m writing it here for future reference.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co">#! /usr/bin/env bash</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="co"># remove containers</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="ex">docker</span> ps <span class="at">--all</span> <span class="at">--format</span> <span class="st">&quot;{%raw%}{{.ID}}{%endraw%}&quot;</span> <span class="kw">|</span> <span class="fu">xargs</span> docker rm</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="co"># remove images</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="ex">docker</span> images <span class="at">--format</span> <span class="st">&quot;{%raw%}{{.ID}}{%endraw%}&quot;</span> <span class="kw">|</span> <span class="fu">xargs</span> docker rmi <span class="at">-f</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="co"># remove volumes</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="ex">docker</span> volume prune</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="co"># remove build cache</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="ex">docker</span> builder prune</span></code></pre></div>
    ]]></content>
    
</entry>
<entry>
    <title>Statically Sized Higher-kinded Polymorphism</title>
    <link href="https://blog.ielliott.io/sized-hkts" />
    
    <id>https://blog.ielliott.io/sized-hkts</id>
    
    <published>2020-07-07T00:00:00Z</published>
    <updated>2020-07-07T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/sized-hkts"><![CDATA[<p>
  Memory-sensitive languages like C++ and Rust use compile-time information to calculate
  sizes of datatypes. These sizes are used to inform alignment, allocation, and calling conventions in ways
  that improve runtime performance. Modern languages in this setting support generic types, but so far
  these languages only allow parameterisation over types, not type constructors. In this article I describe
  how to enable parameterisation over arbitrary type constructs, while still retaining compile-time calculation
  of datatype sizes.
</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/sized-hkts"><![CDATA[
      
      <div class="intro-wrapper">
<div class="intro">
<p>Memory-sensitive languages like C++ and Rust use compile-time information to calculate
sizes of datatypes. These sizes are used to inform alignment, allocation, and calling conventions in ways
that improve runtime performance. Modern languages in this setting support generic types, but so far
these languages only allow parameterisation over types, not type constructors. In this article I describe
how to enable parameterisation over arbitrary type constructs, while still retaining compile-time calculation
of datatype sizes.</p>
<p>The code for this project can be found <a href="https://github.com/LightAndLight/sized-hkts">here</a>.</p>
</div>
<div id="toc">
<h3>Contents</h3>
<ul>
<li><a href="#background">Background</a>
<ul>
<li><a href="#generics">Generics</a></li>
<li><a href="#sizing">Sizing</a></li>
<li><a href="#kinds">Kinds</a></li>
<li><a href="#type-classes">Type Classes</a></li>
<li><a href="#problem-statement">Problem Statement</a></li>
</ul></li>
<li><a href="#solution">Solution</a></li>
<li><a href="#conclusion">Conclusion</a></li>
<li><a href="#references">References</a></li>
</ul>
</div>
</div>
<h2 id="background"><a href="#background">Background</a></h2>
<h3 id="generics"><a href="#generics">Generics</a></h3>
<p>Many typed languages support some form of generic (parameterised) datatypes. This ability to abstract
over types is known as ‘parametric polymorphism’ (polymorphism for short). In Rust, for example, one
can define type of polymorphic pairs as <code>struct Pair&lt;A, B&gt;(fst: A, snd: B)</code>. In this definition, <code>A</code> and <code>B</code> are type
variables (or type parameters), and can be substituted for other types:
<code>Pair&lt;bool, bool&gt;</code>, <code>Pair&lt;bool, char&gt;</code>, and <code>Pair&lt;String, int32&gt;</code> are all valid pairs.</p>
<p>The name of a type, without any parameters, is known as a type constructor. <code>Pair</code> is not a type on its own;
<code>Pair&lt;A, B&gt;</code> (for some types <code>A</code> and <code>B</code>) is. The number of types required to ‘complete’ a type constructor is known
as its arity (so <code>Pair</code> has arity 2). The arity of a type constructor must always be respected; it’s an error to
provide greater or fewer type parameters than are expected. For example, <code>Pair&lt;bool&gt;</code> and
<code>Pair&lt;char, int32, String&gt;</code> are invalid.</p>
<h3 id="sizing"><a href="#sizing">Sizing</a></h3>
<p>When using C++ or Rust, the compiler will calculate how many bytes of memory each datatype requires. Simple
types like <code>int32</code> and <code>bool</code> have a constant size; 4 bytes and 1 byte respectively. The size of datatypes
built using of other simple types is easy to calculate. The simplest way to calculate the size of a struct
is to sum the sizes of the fields, and the simplest way to calculate the size of an enum (or tagged union)
is to find the largest variant, and add 1 (for a tag byte). This is rarely the exact formula used by production
compilers, because they take <a href="https://en.wikipedia.org/wiki/Data_structure_alignment">alignment</a> into account.
This article will assume the simple sizing formula, because the results can easily be adapted to more nuanced
formulae.</p>
<p>The size of a datatype like <code>struct TwoInts(x: int32, y: int32)</code> is known immediately at its definition. <code>TwoInts</code>
requires 8 bytes of memory. On the other hand, the size of a generic datatype is not always known at its definition.
What is the size of <code>struct Pair&lt;A, B&gt;(fst: A, snd: B)</code>? It’s the size of <code>A</code> plus the size of <code>B</code>, for some
unknown <code>A</code> and <code>B</code>.</p>
<p>This difficulty is usually addressed by only generating code for datatypes and functions when all the generic
types have been replaced with concrete types. This process is known as monomorphisation. If the program contains a
<code>Pair(true, true)</code>, then the compiler will generate
a new type <code>struct PairBoolBool(fst: bool, snd: bool)</code> whose size is statically known. If <code>Pair(true, true)</code>
is passed to a function <code>fn swap&lt;A, B&gt;(p: Pair&lt;A, B&gt;) -&gt; Pair&lt;B, A&gt;</code>, then the compiler generates a new
function <code>fn swapBoolBool(p: PairBoolBool) -&gt; PairBoolBool</code>. Because this new function only uses types with known
sizes, the code for memory allocation and calling conventions can be generated correctly.</p>
<p>There are also generic types that <em>don’t</em> depend on the size of their parameters. An example of
this is the pointer, commonly known in Rust as <code>Box&lt;A&gt;</code>. A pointer has the same size (often 4 or 8 bytes depending
on your CPU) regardless of what it points to. But in order to allocate a new pointer, the size of the item must
be known.</p>
<p>For each generic datatype or function, the compiler keeps track of which type variables are important for sizing
calculations. The specifics of this is discussed in the <a href="#type-classes">Type Classes</a> section.</p>
<h3 id="kinds"><a href="#kinds">Kinds</a></h3>
<p>A consequence of all this is that in these languages, type variables can only stand for types. But there
are good reasons to have type variables that stand for type constructors, too:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> One<span class="op">&lt;</span>A<span class="op">&gt;</span>(A)</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span> <span class="op">&lt;</span>A<span class="op">&gt;</span> One<span class="op">&lt;</span>A<span class="op">&gt;{</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  map<span class="op">&lt;</span>B<span class="op">,</span> F<span class="op">:</span> <span class="bu">Fn</span>(A) <span class="op">-&gt;</span> B<span class="op">&gt;</span>(<span class="kw">self</span><span class="op">,</span> f<span class="op">:</span> F) <span class="op">-&gt;</span> One<span class="op">&lt;</span>B<span class="op">&gt;</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Two<span class="op">&lt;</span>A<span class="op">&gt;</span>(A<span class="op">,</span> A)</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span> <span class="op">&lt;</span>A<span class="op">&gt;</span> Two<span class="op">&lt;</span>A<span class="op">&gt;{</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>  map<span class="op">&lt;</span>B<span class="op">,</span> F<span class="op">:</span> <span class="bu">Fn</span>(A) <span class="op">-&gt;</span> B<span class="op">&gt;</span>(<span class="kw">self</span><span class="op">,</span> f<span class="op">:</span> F) <span class="op">-&gt;</span> Two<span class="op">&lt;</span>B<span class="op">&gt;</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Three<span class="op">&lt;</span>A<span class="op">&gt;</span>(A<span class="op">,</span> A<span class="op">,</span> A)</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span> <span class="op">&lt;</span>A<span class="op">&gt;</span> Three<span class="op">&lt;</span>A<span class="op">&gt;{</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>  map<span class="op">&lt;</span>B<span class="op">,</span> F<span class="op">:</span> <span class="bu">Fn</span>(A) <span class="op">-&gt;</span> B<span class="op">&gt;</span>(<span class="kw">self</span><span class="op">,</span> f<span class="op">:</span> F) <span class="op">-&gt;</span> Three<span class="op">&lt;</span>B<span class="op">&gt;</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Here are some 1-arity container types. The only difference between these datatypes is the number of elements
they contain. They all support a <code>map</code> operation, which applies a function to all the datatype’s elements. Functions
that use <code>map</code> need to be implemented once for each type, even when their implementations are identical:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> incrOne(x<span class="op">:</span> One<span class="op">&lt;</span>int32<span class="op">&gt;</span>) <span class="op">-&gt;</span> One<span class="op">&lt;</span>int32<span class="op">&gt;</span> <span class="op">{</span> x<span class="op">.</span>map(<span class="op">|</span>n<span class="op">|</span> n <span class="op">+</span> <span class="dv">1</span>) <span class="op">}</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> incrTwo(x<span class="op">:</span> Two<span class="op">&lt;</span>int32<span class="op">&gt;</span>) <span class="op">-&gt;</span> Two<span class="op">&lt;</span>int32<span class="op">&gt;</span> <span class="op">{</span> x<span class="op">.</span>map(<span class="op">|</span>n<span class="op">|</span> n <span class="op">+</span> <span class="dv">1</span>) <span class="op">}</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> incrThree(x<span class="op">:</span> Three<span class="op">&lt;</span>int32<span class="op">&gt;</span>) <span class="op">-&gt;</span> Three<span class="op">&lt;</span>int32<span class="op">&gt;</span> <span class="op">{</span> x<span class="op">.</span>map(<span class="op">|</span>n<span class="op">|</span> n <span class="op">+</span> <span class="dv">1</span>) <span class="op">}</span></span></code></pre></div>
<p>To remedy this, there must first be a way to abstract over the type constructors, so that the code can
be written <em>once</em> and for all:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> incr<span class="op">&lt;</span>F<span class="op">&gt;</span>(x<span class="op">:</span> F<span class="op">&lt;</span>int32<span class="op">&gt;</span>) <span class="op">-&gt;</span> F<span class="op">&lt;</span>int32<span class="op">&gt;</span> <span class="op">{</span> x<span class="op">.</span>map(<span class="op">|</span>n<span class="op">|</span> n <span class="op">+</span> <span class="dv">1</span>) <span class="op">}</span> <span class="co">// when F&lt;A&gt; has map, for all types A</span></span></code></pre></div>
<p>Then, there must be some way to rule out invalid types. For example, replacing <code>F</code> with <code>bool</code> in <code>F&lt;int32&gt;</code>
is invalid, because <code>bool&lt;int32&gt;</code> is not a type. This is the job of kinds<sup><a href="#reference-constructor-classes" id="reference-constructor-classes:1">1</a></sup>.</p>
<p>Kinds describe the ‘shape’ of types (and type constructors) in the same way that types describe the ‘shape’
of values. A type’s kind determines whether or not it takes any parameters. Here’s the syntax of kinds:</p>
<pre><code>kind ::=
  Type
  kind -&gt; kind</code></pre>
<p>Types that take no arguments (like <code>bool</code>, <code>char</code>, and <code>String</code>) have kind <code>Type</code>. Types that take one argument,
like <code>One</code>, have kind <code>Type -&gt; Type</code>. In the code for <code>incr</code> above, <code>F</code> implicitly has kind <code>Type -&gt; Type</code>. Types
that take more than one argument are represented in <a href="https://en.wikipedia.org/wiki/Currying">curried form</a>. This
means that <code>Two</code> has kind <code>Type -&gt; Type -&gt; Type</code>, not <code>(Type, Type) -&gt; Type</code>. <code>Three</code> has kind <code>Type -&gt; Type -&gt; Type -&gt; Type</code>,
and so on.</p>
<p>Curried type constructors are standard in this setting, but not <em>necessary</em>. The results in this article could
also be applied to a setting with uncurried type constructors, at cost to expressiveness or implementation complexity.</p>
<p>Kinds put types and type constructors on equal footing. For the remainder of the article, both concepts will be
referred to as types. The kind becomes the distinguishing feature. For example, “type constructor of arity 2” would
be replaced by “type of kind <code>Type -&gt; Type -&gt; Type</code>”.</p>
<p>Some final jargon: types with a kind other than <code>Type</code> are known as ‘higher-kinded types’, and parameterising
over higher-kinded types is known as ‘higher-kinded polymorphism’.</p>
<h3 id="type-classes"><a href="#type-classes">Type Classes</a></h3>
<p>Rust uses <a href="https://blog.rust-lang.org/2015/05/11/traits.html">traits</a> to coordinate sizing calculations. Each
datatype implicitly receives an implementation of the <code>Sized</code> trait, and every type variable that is relevant for
a sizing calculation is given a <code>Sized</code> bound. This means that trait resolution, an already useful feature, can
be re-used to perform size calculations.</p>
<p>Closely related to traits is the functional programming concept of type classes<sup><a href="#reference-constructor-classes" id="reference-constructor-classes:2">1</a></sup>. There are differences between the two,
but those differences don’t impact the results of this article. Type classes will prove a more convenient language
in which to discuss these ideas.</p>
<p>A type class (or trait) can be considered a predicate on types. A type class constraint (or trait bound) is an assertion
that the predicate must be true. For each constraint that is satisfied, there is corresponding ‘evidence’ that the
predicate is true.</p>
<p>When a type <code>T</code> has a <code>Sized</code> constraint, it is being asserted that the statement “<code>T</code> has a known size” is true. For
brevity, this will be written as <code>Sized T</code>. When this statement satisfied (for instance, when <code>T</code> is <code>int32</code>), the
evidence is produced is <em>the actual size</em> of <code>T</code> (when <code>Sized int32</code> is satisfied, the evidence
is the number <code>4</code> - the size of <code>int32</code>).</p>
<p>Generic types like <code>Two&lt;A&gt;</code> have a size that depends on their type parameter. In terms of constraints, it can
be said that <code>Sized A</code> <em>implies</em> <code>Sized Two&lt;A&gt;</code>. If <code>A</code> is <code>int32</code>, then its size is <code>4</code>, which implies that
<code>Two&lt;int32&gt;</code> has a size of <code>4 + 4 = 8</code>. Similarly, of <code>Pair</code> it can be said that <code>Sized A</code> implies [ <code>Sized B</code> implies
<code>Sized Pair&lt;A, B&gt;</code> ]. There is a choice between a curried an uncurried version; it could also be said that
[ <code>Sized A</code> <em>and</em> <code>Sized B</code> ] implies <code>Sized Pair&lt;A, B&gt;</code>, but the curried version will be used for convenience.</p>
<p>Note that type <em>constructors</em> don’t have a size. In other words, only types of kind <code>Type</code> have a size. A type constructor
such as <code>Two</code> (of kind <code>Type -&gt; Type</code>) has a size <em>function</em>. Given the sizes of the type constructor’s parameters,
a size function computes the size of the resulting datatype. <code>Two</code>’s size function is <code>\a -&gt; a + a</code>. <code>Pair</code>’s size
function <code>\a -&gt; b -&gt; a + b</code> (it could also be <code>\(a, b) -&gt; a + b</code> in an uncurried setting).</p>
<h3 id="problem-statement"><a href="#problem-statement">Problem Statement</a></h3>
<p>With the background out of the way, the specific problem can be stated:</p>
<p>When a type of kind <code>Type</code> is relevant for a size calculation, it is given a <code>Sized</code> constraint, which will be
satisfied with a concrete size as evidence. What is the equivalent notion of constraint and evidence for
higher-kinded types that contribute to size calculations?</p>
<h2 id="solution"><a href="#solution">Solution</a></h2>
<p>An elegant solution to this problem can found by introducing quantified class constraints<sup><a href="#reference-quantified-constraints" id="reference-quantified-constraints:1">2</a></sup>. Quantified constraints
are an extension to type classes that add implication and quantification to the language of constraints, and corresponding
notions of evidence.</p>
<p>Here’s new syntax of quantified size constraints:</p>
<pre><code>constraint ::=
  Sized type               (size constraint)
  constraint =&gt; constraint (implication constraint)
  forall A. constraint     (quantification constraint)</code></pre>
<p>The evidence for a constraint <code>c1 =&gt; c2</code> is a function that takes evidence for <code>c1</code> and produces evidence for <code>c2</code>, and the
evidence for <code>forall A. c</code> is just the evidence for <code>c</code>. The evidence for quantification constraints is a bit more nuanced
in general, but this description is accurate when only considering size constraints.</p>
<p>Concretely, this means that the sizing rules for higher-kinded types can now be expressed using constraints, and size
calculations involving higher-kinded types can be performed using type class resolution. It is now the
case that <code>forall A. Sized A =&gt; Sized Two&lt;A&gt;</code>, and the evidence for this constraint is the function <code>\a -&gt; a + a</code>.
The relevant constraint for <code>Pair</code> is <code>forall A. forall B. Sized A =&gt; Sized B =&gt; Sized Pair&lt;A, B&gt;</code> with evidence function
<code>\a b -&gt; a + b</code>.</p>
<p>This extends to types of <em>any</em> kind. For all types, there is a mechanical way to derive an appropriate size constraint based
only on type’s kind;
<code>T</code> of kind <code>Type</code> leads to <code>Sized T</code>, <code>U</code> of kind <code>Type -&gt; Type</code> leads to <code>forall A. Sized A =&gt; Sized U&lt;A&gt;</code>, and so on. In
datatypes and functions, any size-relevant type variables can be assigned a size constraint in this way, and the compiler
will use this extra information when monomorphising definitions.</p>
<p><a href="https://github.com/LightAndLight/sized-hkts">sized-hkts</a> is a minimal compiler that implements these ideas. It supports
higher-kinded polymorphism, functions and algebraic datatypes, and compiles to C. Kinds and size constraints are inferred,
requiring no annotations from the user.</p>
<p>Here’s some example code that illustrates the
<a href="https://reasonablypolymorphic.com/blog/higher-kinded-data/">higher-kinded data</a> pattern
(<a href="https://github.com/LightAndLight/sized-hkts/blob/master/examples/ex2.src">source</a>, <a href="https://github.com/LightAndLight/sized-hkts/blob/master/examples/ex2.out">generated C code</a>):</p>
<pre><code>enum ListF f a { Nil(), Cons(f a, ptr (ListF f a)) }
enum Maybe a { Nothing(), Just(a) }
struct Identity a = Identity(a)

fn validate&lt;a&gt;(xs: ListF Maybe a) -&gt; Maybe (ListF Identity a) {
  match xs {
    Nil() =&gt; Just(Nil()),
    Cons(mx, rest) =&gt; match mx {
      Nothing() =&gt; Nothing(),
      Just(x) =&gt; match validate(*rest) {
        Nothing() =&gt; Nothing(),
        Just(nextRest) =&gt; Just(Cons(Identity(x), new[nextRest]))
      }
    }
  }
}

fn main() -&gt; int32 {
  let
    a = Nil();
    b = Cons(Nothing(), new[a]);
    c = Cons(Just(1), new[b])
  in
    match validate(c) {
      Nothing() =&gt; 11,
      Just(xs) =&gt; match xs {
        Nil() =&gt; 22,
        Cons(x, rest) =&gt; x.0
      }
    }
}</code></pre>
<p>This code defines a linked list whose elements are wrapped in a generic ‘container’ type. It defines two possible
container types: <code>Maybe</code>, which is a possibly-empty container, and <code>Identity</code>, the single-element container.
<code>validate</code> takes a list whose elements are wrapped in <code>Maybe</code> and tries to replace all the <code>Just</code>s with <code>Identity</code>s.
If any of the elements of the list are <code>Nothing</code>, then the whole function returns <code>Nothing</code>.</p>
<p>Points of interest in the generated code include:</p>
<ul>
<li>5 types are generated, corresponding to:
<code>ListF Maybe int32</code>, <code>ListF Identity int32</code>, <code>Maybe int32</code>, <code>Identity int32</code>, and <code>Maybe (ListF Identity int32)</code></li>
<li>Only 1 version of <code>validate</code> is generated, because it is only used at one instantiation of <code>a</code>.</li>
<li>The generated code makes no use of <code>sizeof</code>; the datatype sizes are known after typechecking and inlined during
code generation. The compiler knows that <code>ListF Maybe int32</code> is naively <code>14</code> bytes wide
(<code>1 + max(1, 1 + 4) + 8</code>), whereas <code>ListF Identity int32</code> is <code>13</code> bytes wide (<code>max(1, 1 + 4) + 8</code>).</li>
<li>The datatype sizes are not necessarily consistent with <code>sizeof</code>, because they ignore alignment for simplicity.
At this point, factoring alignment into the size calculations is straightforward.</li>
</ul>
<h2 id="conclusion"><a href="#conclusion">Conclusion</a></h2>
<p>Quantified class constraints provide an elegant framework for statically-sized higher-kinded types. On its own, this
can raise the abstraction ceiling for high-performance languages, but it also serves as the groundwork for ‘zero-cost’
versions of functional programming abstractions such as Functor, Applicative, and Traversable.</p>
<p>This work shows it’s definitely possible for Rust to support higher-kinded types in a reasonable manner, but
there are some less theoretical reasons why that might not be a good idea in practice. Adding ‘quantified trait bounds’
would require new syntax, and represents an additional concept for users to learn. Adding a kind system to Rust
would also be a controversial change; choosing to keep types uncurried would disadvantage prospective users of the
system, and changing to curried types would require rethinking of syntax and educational materials to maintain Rust’s
high standard of user experience.</p>
<h2 id="references"><a href="#references">References</a></h2>
<ol type="1">
<li><p><span id="reference-constructor-classes">Jones, M. P. (1995). A system of constructor classes:
overloading and implicit higher-order polymorphism. <em>Journal of functional programming</em>, 5(1),
1-35.</span> <a href="#reference-constructor-classes:1">↩︎<sup>1</sup></a> <a href="#reference-constructor-classes:2">↩︎<sup>2</sup></a></p></li>
<li><p><span id="reference-quantified-constraints">Bottu, G. J., Karachalias, G., Schrijvers, T.,
Oliveira, B. C. D. S., &amp; Wadler, P. (2017). Quantified class constraints. <em>ACM SIGPLAN Notices</em>,
52(10), 148-161.</span> <a href="#reference-quantified-constraints:1">↩︎</a></p></li>
</ol>
    ]]></content>
    
</entry>
<entry>
    <title>Lambdas are Codatatypes</title>
    <link href="https://blog.ielliott.io/lambdas-are-codatatypes" />
    
    <id>https://blog.ielliott.io/lambdas-are-codatatypes</id>
    
    <published>2019-07-01T00:00:00Z</published>
    <updated>2019-07-01T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/lambdas-are-codatatypes"><![CDATA[<p>I was first clued into this a while ago by
<a href="https://existentialtype.wordpress.com/2011/04/24/the-real-point-of-laziness/">a comment on Bob Harper’s blog</a> that “exponentials are coinductive”, but it only really clicked for me today. Let’s get into it.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/lambdas-are-codatatypes"><![CDATA[
      
      <p>I was first clued into this a while ago by
<a href="https://existentialtype.wordpress.com/2011/04/24/the-real-point-of-laziness/">a comment on Bob Harper’s blog</a> that “exponentials are coinductive”, but it only really clicked for me today. Let’s get into it.</p>
<h2 id="datatypes"><a href="#datatypes">Datatypes</a></h2>
<h3 id="defining-them"><a href="#defining-them">Defining them</a></h3>
<p>When you define a datatype, you list the ways to construct values of that type. For example,
this definition:</p>
<pre><code>data Bool : Type where { 
  True;
  False
}</code></pre>
<p>says there are two ways to construct a <code>Bool</code>: <code>True</code> and <code>False</code>.</p>
<p>Similarly, this definition:</p>
<pre><code>data These (a : Type) (b : Type) : Type where { 
  This[a];
  That[b];
  These[a, b]
} </code></pre>
<p>gives three ways to construct a <code>These a b</code> (for any values of <code>a</code> and <code>b</code>). <code>This[0]</code> has type
<code>These Int x</code>, for any <code>x</code>. <code>That[True]</code> has type <code>These x Bool</code> for any <code>x</code>. <code>These[0, True]</code> has
type <code>These Int Bool</code>.</p>
<p>I want to note that constructors aren’t functions; they have a fixed number of arguments and must
be fully applied.</p>
<p>Datatypes can also be defined recursively:</p>
<pre><code>data List (a : Type) : Type where {
  Nil;
  Cons[a, List a]
}</code></pre>
<h3 id="using-them"><a href="#using-them">Using them</a></h3>
<p>The way you construct a value of a datatype is unique to that datatype; there are a finite number of
constructors, and each represents a different way to build a value of that type. In contrast, there is
a universal way to <em>destruct</em> values: pattern matching.</p>
<p>If some expression <code>x</code> has type <code>Bool</code> then we can destruct <code>x</code> using pattern matching:</p>
<pre><code>case x of {
  True -&gt; ...;
  False -&gt; ...
}</code></pre>
<p>A pattern match acknowledges all the ways that a value could have been constructed, and provides
a branch for each possible case. When constructors carry around other values
(like those of <code>These</code> or <code>List</code>), pattern matching is used to write programs that extract and
process the inner values:</p>
<pre><code>case y of {
  This[a] -&gt; f a;
  That[b] -&gt; g b;
  These[c, d] -&gt; h c d
}</code></pre>
<p>When a program is running, the value that is being matched will eventually reduce to a constructor form:</p>
<pre><code>case (These 0 True) of {
  This[a] -&gt; f a;
  That[b] -&gt; g b;
  These[c, d] -&gt; h c d
}</code></pre>
<p>at which point, the appropriate branch is selected and the contents of the constructor are substituted
to the right of the <code>-&gt;</code>. The above code will pick the <code>These</code> branch, substituting <code>0</code> for <code>c</code> and <code>True</code>
for <code>d</code>, so that the final result is <code>h 0 True</code>.</p>
<p>Pattern matching is enough to process non-recursive datatypes, but recursive datatypes require recursive
function definitions:</p>
<pre><code>sum : List Int -&gt; Int
sum n =
  case n of {
    Nil -&gt; 0;
    Cons[x, xs] -&gt; x + sum xs
  }</code></pre>
<p>Hopefully this is all familiar to you. I’ve covered all this so that it contrasts with <em>codatatypes</em>.</p>
<h2 id="codatatypes"><a href="#codatatypes">Codatatypes</a></h2>
<p>Codatatypes are the dual to datatypes. Formally, this means a lot of things that I don’t yet understand. What
follows is how this duality arises in practise.</p>
<p>To begin, I’d like to share some hand-wavy intuition for the concepts I’m
discussing.</p>
<p>Datatypes <em>are</em>. They’re finite, fully-evaluated structures. They’re inert; they just exist and won’t ever
“do anything”. Haskell doesn’t have true ‘datatypes’ in this sense because its constructors don’t force their
arguments to be evaluated, which means you can hide computations inside them. Haskell lets you partially
apply constructors, which further diverges from what I’ve laid out here.</p>
<p>Codatatypes <em>do</em>. They have ‘potential energy’; they have the capacity to do more work when prodded. Haskell’s
‘datatypes’ are more codata-like in this respect because they can contain suspended computations.</p>
<h3 id="defining-them-1"><a href="#defining-them-1">Defining them</a></h3>
<p>Since datatypes are defined by their constructors, codatatypes will be defined by their <em>destructors</em>.</p>
<p>This definition:</p>
<pre><code>codata Pair (a : Type) (b : Type) : Type where {
  fst : a;
  snd : b
}</code></pre>
<p>says that there are two ways to <em>destruct</em> a <code>Pair a b</code> (for any <code>a</code> and <code>b</code>). If some expression <code>x</code> has
type <code>Pair a b</code>, then <code>x.fst</code> has type and <code>a</code>, and <code>x.snd</code> has type a <code>b</code>.</p>
<p><code>Pair</code> really is pair, it has just been defined by the ways you can pull things out of it- you can either
extract the first thing, or you can extract the second.</p>
<p>I also want to note that destructors aren’t functions, either. You can’t partially apply a destructor, and
they’re not first-class.</p>
<p>Codatatypes can also be recursive:</p>
<pre><code>codata Stream (a : Type) : Type where {
  head : a;
  tail : Stream a
}</code></pre>
<p>A stream is like an infinite list; every stream value contains a head and a tail, and no matter how many
times you extract the tail, there will always be another stream waiting for you.</p>
<h3 id="using-them-1"><a href="#using-them-1">Using them</a></h3>
<p>There is a universal way to destruct datatypes, and there is a universal way to <em>construct</em> <em>codatatypes</em>.
For lack of a better term, you can call it ‘copattern matching’. Here’s how you would construct a
<code>Pair Int Bool</code>:</p>
<pre><code>cocase Pair Int Bool of {
  fst -&gt; 0;
  snd -&gt; True
}</code></pre>
<p>A copattern match acknowledges every way it could be destructed, and provides a branch for each case.
Remember, copattern matching <em>constructs</em> values. The above code is a value that produces <code>0</code> when
destructed using <code>fst</code>, and <code>True</code> when destructed using <code>snd</code>. It is defining a pair of <code>0</code> with <code>True</code>.</p>
<p>When a program is running, a value that is being destructed will eventually reduce to a copattern match form.
So <code>x.fst</code> might reduce to <code>(cocase Pair Int Bool of { fst -&gt; 0; snd -&gt; True }).fst</code>. At this point,
the appropriate branch in the copattern match will be chosen, and the right hand side of the <code>-&gt;</code> will be
selected. In this case, <code>(cocase Pair Int Bool of { fst -&gt; 0; snd -&gt; True }).fst</code> reduces to <code>0</code>.</p>
<p>Recursive codatatypes like <code>Stream</code> need to be constructed by recursive definitions:</p>
<pre><code>countFrom : Int -&gt; Stream Int
countFrom n =
  cocase Stream Int of {
    head -&gt; n;
    tail -&gt; countFrom (n+1)
  }</code></pre>
<p><code>countFrom 0</code> produces an infinite stream of integers starting at <code>0</code>. However, it doesn’t spin forever,
trying to construct the entire stream in one go. This is because a lone copattern match won’t reduce; reduction
only continues after a destructor has been applied and the correct branch has been selected. Because of
this, codatatypes can represent infinite values that are only generated on demand.</p>
<p>Datatype constructors can carry around values, and so can codatatype <em>destructors</em>.
Here’s what that looks like:</p>
<pre><code>codata Lambda (a : Type) (b : Type) : Type where {
  apply[a] : b
}</code></pre>
<p>There is one way to destruct a value of type <code>Lambda a b</code> called <code>apply</code>, and this destructor takes a
parameter. If <code>f</code> has type <code>Lambda a b</code>, and <code>x</code> has type <code>a</code>, then <code>f.apply[x]</code> has type <code>b</code>.</p>
<p>To create a value of type <code>Lambda a b</code>, you would use a copattern match:</p>
<pre><code>cocase Lambda a b of {
  apply[x] -&gt; ...
}</code></pre>
<p>The destructor’s parameter is abstract and is to be filled by the value that the destructor will be carrying.
For example, <code>(cocase Lambda Int Int of { apply[x] -&gt; x + 1 }).apply[2]</code> selects the appropriate branch
(there’s only one), and substitutes <code>2</code> for <code>x</code> to the right of the <code>-&gt;</code>. It steps to <code>2 + 1</code>.</p>
<p>So lambdas can be defined as codatatypes. Their destructor corresponds to function application, and
copattern matching corresponds to abstraction. This is awesome!</p>
    ]]></content>
    
</entry>
<entry>
    <title>Configuring Agda's standard library on NixOS</title>
    <link href="https://blog.ielliott.io/agda-nixos" />
    
    <id>https://blog.ielliott.io/agda-nixos</id>
    
    <published>2019-05-17T23:49:00Z</published>
    <updated>2019-05-17T23:49:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/agda-nixos"><![CDATA[<p>I’ve been using Agda on NixOS for a while (mostly via <code>agda-mode</code> in Emacs), but I remember it was a bit
difficult to get going the very first time. Hopefully this becomes a searchable reference
to getting it all set up quickly.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/agda-nixos"><![CDATA[
      
      <p>I’ve been using Agda on NixOS for a while (mostly via <code>agda-mode</code> in Emacs), but I remember it was a bit
difficult to get going the very first time. Hopefully this becomes a searchable reference
to getting it all set up quickly.</p>
<hr />
<p>Prerequisites:</p>
<ul>
<li>Working NixOS installation</li>
<li>Agda &gt;=2.5.1</li>
</ul>
<ol type="1">
<li><p>Install <code>AgdaStdlib</code> globally</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co"># /etc/nixos/configuration.nix</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="op">.</span>..</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>environment<span class="op">.</span>systemPackages = <span class="kw">with</span> pkgs<span class="op">;</span> <span class="op">[</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">.</span>..</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>  AgdaStdLib</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="op">]</span>;</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="op">.</span>..</span></code></pre></div></li>
<li><p>Link <code>/share/agda</code></p>
<div class="sourceCode" id="cb2"><pre class="sourceCode nix"><code class="sourceCode nix"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># /etc/nixos/configuration.nix</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="op">.</span>..</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>environment<span class="op">.</span>pathsToLink = <span class="op">[</span> <span class="st">&quot;/share/agda&quot;</span> <span class="op">]</span>;</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="op">.</span>..</span></code></pre></div></li>
<li><p>Rebuild: <code>sudo nixos-rebuild switch</code></p></li>
<li><p>Navigate to or create <code>~/.agda</code></p></li>
<li><p>Create 3 files in <code>~/.agda</code>: <code>defaults</code>, <code>libraries</code>, <code>standard-library.agda-lib</code></p>
<pre class="shell_session"><code>[isaac:~/.agda]$ touch defaults
[isaac:~/.agda]$ touch libraries
[isaac:~/.agda]$ touch standard-library.agda-lib</code></pre></li>
<li><p>Edit <code>standard-library.agda-lib</code></p>
<pre class="shell_session"><code>[isaac:~/.agda]$ cat &lt;&lt; EOF &gt;&gt; standard-library.agda-library
&gt; name: standard-library
&gt; include: /run/current-system/sw/share/agda/
&gt; EOF</code></pre>
<p>This says that there is a library located at the relevant NixOS path.</p></li>
<li><p>Edit <code>libraries</code></p>
<pre class="shell_session"><code>[isaac:~/.agda]$ echo &quot;/home/isaac/.agda/standard-library.agda-lib&quot; &gt;&gt; libraries</code></pre>
<p>This registers the <code>.agda-lib</code> file with Agda.</p></li>
<li><p>Edit <code>defaults</code></p>
<pre class="shell_session"><code>[isaac:~/.agda]$ echo &quot;standard-library&quot; &gt;&gt; defaults</code></pre>
<p>This tells Agda to include the <code>standard-library</code> library by default.</p></li>
</ol>
<p>To check your installation, try compiling a simple Agda file:</p>
<pre class="shell_session"><code>[isaac:~]$ cat &lt;&lt; EOF &gt;&gt; Test.agda
&gt; module Test where
&gt; open import Data.Nat
&gt; EOF
[isaac:~]$ agda Test.agda
Checking Test (/home/isaac/Test.agda).
</code></pre>
<p>Let me know whether or not this works for you :)</p>
    ]]></content>
    
</entry>
<entry>
    <title>Conditional Probabilities and Obnoxious White Guys</title>
    <link href="https://blog.ielliott.io/conditional-probabilities-obnoxious-white-guys" />
    
    <id>https://blog.ielliott.io/conditional-probabilities-obnoxious-white-guys</id>
    
    <published>2019-05-05T00:00:00Z</published>
    <updated>2019-05-05T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/conditional-probabilities-obnoxious-white-guys"><![CDATA[<p>In <a href="https://twitter.com/DrEugeniaCheng/status/1124795257814691841">this Twitter thread</a>,
Eugenia Cheng talks about how she presented at a conference for women in STEM, and was
confronted by a white guy who felt ‘called out’ by some of her anecdotes. Apparently, she
described interactions with obnoxious individuals in a professional setting, and noted that
they were all white guys. Ironically, the guy raised the issue in such a way that he was added
to the list of anecdotes.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/conditional-probabilities-obnoxious-white-guys"><![CDATA[
      
      <p>In <a href="https://twitter.com/DrEugeniaCheng/status/1124795257814691841">this Twitter thread</a>,
Eugenia Cheng talks about how she presented at a conference for women in STEM, and was
confronted by a white guy who felt ‘called out’ by some of her anecdotes. Apparently, she
described interactions with obnoxious individuals in a professional setting, and noted that
they were all white guys. Ironically, the guy raised the issue in such a way that he was added
to the list of anecdotes.</p>
<p>Later, Dr. Cheng <a href="https://twitter.com/DrEugeniaCheng/status/1124805201452515328">clearly states her position</a>.</p>
<blockquote>
<p>…people being obnoxious to me professionally are almost all white guys…</p>
</blockquote>
<p>Many people take her word for it, but some (particularly white guys) are skeptical. I’m going to
quickly examine some degrees of belief in her claim through the lens of probability theory.</p>
<hr />
<p>To begin, I want to explain why I have bothered to think about this. I believe Eugenia’s statement;
I have no reason to think that she’s mistaken or lying. But in spite of this, for some reason, I
empathised with the aforementioned white guy. Why? My unease wasn’t caused by any conscious
reasoning process; it just seemed to arise of its own accord.</p>
<p>I’ve been learning that <a href="https://medium.com/@ThingMaker/focusing-for-skeptics-6b949ef33a4f">“focusing”</a>
can be a helpful way to unpack these confusing feelings. I didn’t go all-out focusing on this,
but throughout my inquiry I made sure to be conscious of how my reasoning interacted with the feeling.</p>
<p>To paint a better picture of the feeling, it was something like:</p>
<ul>
<li>“Tenseness”</li>
<li>“Singled out”</li>
<li>“I feel like I’m about to fight something”</li>
</ul>
<p>To re-iterate: I don’t think these feelings were rational, which is why I decided to keep digging. Let’s
get into it. I’m going to assume basic familiarity with probability theory, and an understanding that
<a href="https://www.lesswrong.com/posts/f6ZLxEWaankRZ2Crv/probability-is-in-the-mind">probability is in the mind</a>.</p>
<p>I think Eugenia’s claim is this:
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">person was white guy</mtext><mspace width="0.278em"></mspace><mo stretchy="false" form="prefix">|</mo><mspace width="0.278em"></mspace><mtext mathvariant="normal">interacted with obnoxious person</mtext><mo stretchy="false" form="postfix">)</mo><mo>&gt;</mo><mn>0.5</mn></mrow><annotation encoding="application/x-tex">P( \text{person was white guy} \; | \; \text{interacted with obnoxious person} ) &gt; 0.5</annotation></semantics></math>. In other
words: of all the obnoxious researchers she’s interacted with, most are white guys. Let’s look at the
conditional probability in terms of Bayes’ Theorem:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="prefix">|</mo><mi>O</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mfrac><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="prefix">|</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="postfix">)</mo></mrow><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="postfix">)</mo></mrow></mfrac></mrow><annotation encoding="application/x-tex"> P(WG | O) = \frac{P(O | WG) \cdot P(WG)}{P(O)} </annotation></semantics></math></p>
<p>To start with, I’ll plug in my estimates to show why I don’t disagree with her.</p>
<p>I think mathematics is pretty
male-dominated, so I’m going to say <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mn>0.7</mn></mrow><annotation encoding="application/x-tex">P(WG) = 0.7</annotation></semantics></math>. Seven in ten researchers she meets are white dudes.</p>
<p>Let’s then say that <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mn>0.1</mn></mrow><annotation encoding="application/x-tex">P(O) = 0.1</annotation></semantics></math> — one in ten researchers she interacts with are jerks (am I optimistic or
pessimistic about the academic community?).</p>
<p>Lastly there’s <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="prefix">|</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">P(O | WG)</annotation></semantics></math>: of all the white male researchers she meets, how many act
obnoxiously? I’m going to be charitable here and say (for demonstration purposes) that the white guys are
no more jerkish on average, so one in ten white male researchers she interacts with are jerks to her.
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="prefix">|</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mn>0.1</mn></mrow><annotation encoding="application/x-tex">P(O | WG) = 0.1</annotation></semantics></math>.</p>
<p>Now, compute!</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><mspace width="0.222em"></mspace></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mfrac><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="prefix">|</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="postfix">)</mo><mo>⋅</mo><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="postfix">)</mo></mrow><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="postfix">)</mo></mrow></mfrac></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><mo>=</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mspace width="0.278em"></mspace><mfrac><mrow><mn>0.1</mn><mo>⋅</mo><mn>0.7</mn></mrow><mn>0.1</mn></mfrac></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><mo>=</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mspace width="0.278em"></mspace><mn>0.7</mn></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{aligned}
~ &amp; \frac{P(O | WG) \cdot P(WG)}{P(O)} \\\\
= &amp; \; \frac{0.1 \cdot 0.7}{0.1} \\\\
= &amp; \; 0.7
\end{aligned}
</annotation></semantics></math></p>
<p>My estimate is consistent with her statement - of all the obnoxious researchers she meets, seven in ten
would be white guys, even when assuming zero racial/gender biases.</p>
<p>Suppose you disagree with me. That is, your estimates are such that <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="prefix">|</mo><mi>O</mi><mo stretchy="false" form="postfix">)</mo><mo>≤</mo><mn>0.5</mn></mrow><annotation encoding="application/x-tex">P(WG | O) \le 0.5</annotation></semantics></math>. There are two ways
to disagree here:</p>
<ol type="1">
<li><p>A lower ratio <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mfrac><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="prefix">|</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="postfix">)</mo></mrow><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="postfix">)</mo></mrow></mfrac><annotation encoding="application/x-tex">\frac{P(O | WG)}{P(O)}</annotation></semantics></math>. You might take
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="prefix">|</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mn>0.07</mn></mrow><annotation encoding="application/x-tex">P(O | WG) = 0.07</annotation></semantics></math>, which means <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="prefix">|</mo><mi>O</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mn>0.49</mn></mrow><annotation encoding="application/x-tex">P(WG | O) = 0.49</annotation></semantics></math>. You might instead take
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mn>0.14</mn></mrow><annotation encoding="application/x-tex">P(O) = 0.14</annotation></semantics></math> for a similar result. Either way, you’re claiming that the fragment of
white male researchers Dr. Cheng meets are nicer on average than the general population of
researchers she has met.</p></li>
<li><p>A lower <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">P(WG)</annotation></semantics></math>, indicating that you think Dr. Cheng interacts with relatively fewer white
male researchers.</p></li>
</ol>
<p>Running through these calculations didn’t give me any closure. I agree on paper, and feel that my estimates are
appropriate. In fact, I would take <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mfrac><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="prefix">|</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="postfix">)</mo></mrow><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="postfix">)</mo></mrow></mfrac><annotation encoding="application/x-tex">\frac{P(O | WG)}{P(O)}</annotation></semantics></math> to be slightly greater than one, to account
for biases like sexism and racism. But that only means I agree more.</p>
<p>The idea that ‘clicked’ with me, that immediately resolved my inner turmoil, was this: somehow I’m implicitly
turning
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="prefix">|</mo><mi>O</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">P(WG | O)</annotation></semantics></math> into <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="prefix">|</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">P(O | WG)</annotation></semantics></math>. <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="prefix">|</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">P(O | WG)</annotation></semantics></math> is the term from which stereotypes are born. If most
of the white guys you meet are jerks, then your <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="prefix">|</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">P(O | WG)</annotation></semantics></math> is high. If you don’t quotient that by the
proportion of people who are rude to you in general, then you have a gratuitous stereotype. If you do then
you’re completely justified in thinking that ‘white guy’ and ‘obnoxious’ are correlated. So I think that somehow
my wires were crossed and I was subconsciously interpreting the conversation as purely a statement about
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>O</mi><mo stretchy="false" form="prefix">|</mo><mi>W</mi><mi>G</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">P(O | WG)</annotation></semantics></math>.</p>
<p>I think this kind of error falls in the category of
<a href="https://en.wikipedia.org/wiki/Attribute_substitution">attribute substitution</a>, and I think it’s pretty common.
For example in <a href="https://www.youtube.com/watch?v=BrK7X_XlGB8">Julia Galef’s video about Bayes’ Theorem</a>, she says that before
students learn Bayes’ Theorem, they often give <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>B</mi><mo stretchy="false" form="prefix">|</mo><mi>A</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">P(B | A)</annotation></semantics></math> when asked for <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false" form="prefix">(</mo><mi>A</mi><mo stretchy="false" form="prefix">|</mo><mi>B</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">P(A | B)</annotation></semantics></math>. I
don’t know how exactly this sort of thing happens — maybe I’ll explore that some other time.</p>
<p>Anyway, I’m glad that my feelings and beliefs are now in sync on this issue.</p>
    ]]></content>
    
</entry>
<entry>
    <title>Learning a Craft</title>
    <link href="https://blog.ielliott.io/learning-a-craft" />
    
    <id>https://blog.ielliott.io/learning-a-craft</id>
    
    <published>2019-02-11T00:00:00Z</published>
    <updated>2019-02-11T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/learning-a-craft"><![CDATA[<p>I remember when I first learned about computer programming, around 2008 or 2009.
I wanted to make games, and asked a search engine. Apparently computer graphics
was way too hard, so I decided I wanted to create browser-based static HTML
games and text-based roguelikes. Having learned that PHP and MySQL exist, I sat
down and brainstormed a setting, classes and roles for characters, and all the
other things that come with fantasy RPGs.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/learning-a-craft"><![CDATA[
      
      <p>I remember when I first learned about computer programming, around 2008 or 2009.
I wanted to make games, and asked a search engine. Apparently computer graphics
was way too hard, so I decided I wanted to create browser-based static HTML
games and text-based roguelikes. Having learned that PHP and MySQL exist, I sat
down and brainstormed a setting, classes and roles for characters, and all the
other things that come with fantasy RPGs.</p>
<p>Soon after, I realised I wasn’t capable of building any of it.</p>
<p>At the time, even the simplest programs were incredibly confusing, and the
complexity of a browser game was far beyond me. I’m lucky that I didn’t give up
on programming after realising I couldn’t build any of my cool ideas. For me,
just being able to make computers do things was enthralling, and my learning
became self-propelled — games be damned.</p>
<p>Contrast this with how I’ve recently approached another activity that I’m
interested in, but very bad at: creative writing. For a while now I’ve wanted to
learn how to tell stories, and this has been my process so far:</p>
<blockquote>
<p>“I want to write stuff.”</p>
<p>“Not just any old stuff, but <em>cool</em> stuff; interesting stuff.”</p>
<p>“But I don’t have any cool ideas!”</p>
<p>“Guess I won’t write about anything then.”</p>
</blockquote>
<p>In other words: I’ve learned <em>nothing</em>, because I haven’t done anything. I’ve
been paralysed by this desire to only make ‘interesting’ things. It’s easy
to imagine that other people have been stuck in similar situations with
programming: someone wants to learn to code, but doesn’t know what to build, or
only wants to work on seriously cool and ground-breaking projects. And I’m sure
it’s not only programming; it seems there’s a common set of problems facing
people who take up a craft. To address this, I’m going to think of advice that I
would give to beginner programmers and generalise it.</p>
<h2 id="drop-your-standards-and-shelve-your-ideas"><a href="#drop-your-standards-and-shelve-your-ideas">Drop your standards and shelve your ideas</a></h2>
<p>At the start of the learning process, you have barely any ability. This means
that by most standards, you will produce a lot of terrible, unskilled work. But
that’s okay, because at this stage each piece of work is a step toward
improvement. Each thing you make exists so that you can figure out how to make
the <em>next</em> one better. Your standards, or
<a href="https://www.youtube.com/watch?v=X2wLP0izeJE">taste</a>, can still point you in
directions for improvement, but your mistakes and shortcomings are not <em>bad
things</em>.</p>
<p>If you have any grand designs, put them on hold. Chances are you don’t have the
ability to see them through right now. Sometimes lofty ideas can help you figure
out which areas to study – if you dream of making a first person shooter then
you should definitely learn about 3D graphics. In general, though, I think it
will help to put the big ideas aside until you’re more skilled.</p>
<h2 id="make-everything"><a href="#make-everything">Make EVERYTHING</a></h2>
<p>When I started coding, I made calculator and to-do list apps, tiny
database-backed webapps and 2D space shooters and brick breakers. None of this
was remotely novel; it was a challenge just to repeat what others had built
before me. Even though I wasn’t building anything original, I was still creating
something that <em>I</em> had never made before, which was a huge learning experience.
Even simple programs, like a calculator, require important fundamental skills
that I didn’t have. I encountered problems that had been solved countless times
by others, but that didn’t diminish the value of solving them for myself.</p>
<p>Getting into this mindset seems especially difficult in ‘creative’ endeavours
like writing, game programming, or visual art. It feels like in these areas,
there’s a big emphasis on being unique, imaginative, and innovative. While this
is a fine standard for experts, it’s the wrong way for beginners to approach a
craft. Making shiny new stuff comes later; right now you need to re-make old
stuff.</p>
<p>Replicating past work doesn’t mean to copy things out line for line. Copy the
idea, and figure out how to fill in the details yourself. When I sat down and
said “I’m going to write a brick breaking game”, I didn’t go and cut sections of
code out of other similar games. I took the un-original concept, broke it into
smaller components, and figured out how to make each of those bits. How do I
display a ball on the screen? How do I make it move? How do I make it bounce?
Each sub-problem required original thinking on my part, and it’s this original
thinking that drove my improvement.</p>
<h2 id="find-joy-in-the-process"><a href="#find-joy-in-the-process">Find joy in the process</a></h2>
<p>Motivation is really important for making consistent progress in a skill, but
not all motivations are equally effective. I think the least sustainable
motivational source (but most common for beginners) is ‘wanting to make
something good’. If this is your main motivation, then you’ll be in a constant
state of discouragement — every piece of work a reminder of your lack of
ability. These little negatives slowly add up until you resent the activity.</p>
<p>A better motivational source is ‘to improve at something’. With this
perspective, you feel accomplishment whenever you notice that your skills have
increased, which happens often for beginners who practise regularly. But
improvement-based motivation isn’t enough on its own; there are periods where
you won’t notice improvement, but it’s important to practise anyway.</p>
<p>The most important and fundamental source of motivation comes from enjoying the
activity itself. If you enjoy the craft regardless of standards of quality or
ability, then it doesn’t matter how ‘bad’ your work is in the beginning, because
producing it is a joy in itself. I’ve spent days and sometimes weeks stuck
trying to make my code work the way I intended, but that’s all okay because it’s
part of the process. At the end of the day I just like making computers do
things.</p>
<hr />
<p>I mainly wrote this for myself, to get a bit of a handle on why I find writing
so difficult and how I can make it easier. I think it has helped. The next thing
I write (not on here) will likely be the literary equivalent of a command-line
calculator program — and that’s okay.</p>
<p><em>All this ‘advice’ may seem obvious to some, or lacking in original insight, and
I’m</em> sure <em>other people have written about these things to greater effect than me.
But that’s beside the point, isn’t it?</em></p>
    ]]></content>
    
</entry>
<entry>
    <title>Writing</title>
    <link href="https://blog.ielliott.io/writing" />
    
    <id>https://blog.ielliott.io/writing</id>
    
    <published>2018-12-29T00:00:00Z</published>
    <updated>2018-12-29T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/writing"><![CDATA[<p>I think writing can help us think better.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/writing"><![CDATA[
      
      <p>I think writing can help us think better.</p>
<p>Not the act of writing itself, but a particular writing process where you take
an idea, think deeply about exactly how you want to express it, and then write
it down. I think the process itself provides part of the value, as a form of
“brain exercise”, but also the end product, as a foundation upon which we can
build more robust ideas.</p>
<p>This post is a funny self-referential exercise where I explore what I’m writing
about as I write it.</p>
<hr />
<p>When I have a thought, I feel pretty confident about it. It seems real and solid
and it feels like I understand it. But most of the time this is an illusion.
If I try to go deeper and ask myself questions like “Why do you think that?” or “Can you
elaborate?” I often find it hard to come up with an answer. When this happens I
say my idea lacks ‘substance’ or ‘structure’. There are no justifications or
consequences bundled along with the thought; it’s kind of empty. Substance is important for
ideas to be meaningful - at best, an insubstantial idea is a platitude, and at
worse, outright nonsense. So if I have an idea, I’d like to give it some meaning
(or figure out that it is actually as empty as it seems).</p>
<p>If I want to uncover the structure of an idea, I need to think more about it. I need to
ask questions and explore perspectives. I’ll have a stack of relevant sub-ideas
that all need to be related to the larger idea. If I tried to do all this in my
head then I wouldn’t get very far. My working memory is really tiny compared to
the ideas I want to tackle. So my first use for writing is as a tool of thought:
I can store all my relevant thoughts onto a page and devote my full attention to
the particular problem at hand. Sound reasoning is an important component of
‘thinking better’, and writing enables me to devote more attention to that
process. Not only can I reason better, but I also have the freedom to reason
<em>more</em>, because I can explore more sub-ideas without getting lost. Writing
allows me to increase the intensity and volume of reasoning, which seems like it
should lead to greater improvement in the area.</p>
<p>In addition to being a personal tool, writing also is used to transfer
information between two different minds, and I think being conscious of this is
an important part of the process. To me, writing seems like a kind of
telepathy. It’s a way to transmit thoughts between minds via a physical medium.
But high fidelity transmission isn’t guaranteed just because you wrote
<em>something</em> down. We need to put words together in a way that makes it more
likely for the telepathy to be successful. I think that to succeed at this
sort of language game requires a clear understanding of the subject matter. When
you understand what you’re talking about, you can play with the descriptions you use
and compare their accuracy, then use the best description in your final work.
But if you don’t understand what you’re
talking about then there’s not much to measure your words against in the first
place. I think that focusing on communication forces us to search for
the ‘essence’ of an idea, which further engages our critical thinking abilities.</p>
<p>My hope is that putting all this effort into exploring and refining an idea
creates new intellectual opportunities in the future. Kind of like taking blobs
of clay and forging them into bricks: if you want to build a tower,
you want to start with the foundation and work up, brick by brick. You won’t get
very high by stacking clay. Similarly, this
writing process might be refining ideas in a way that is necessary to make
further intellectual progress, and that without it, there would be a much lower
ceiling on what we can achieve.</p>
<p>Having written all this down, I think a summary of this process is: the <a href="https://en.wikipedia.org/wiki/Practice_(learning_method)#Deliberate_practice">deliberate
practise</a>
of organising thought, critical thinking, and effective communication. Writing
serves dual purposes: as a tool it enables us to better explore ideas, and treating it
as an end in itself requires us to better understand those ideas.</p>
    ]]></content>
    
</entry>
<entry>
    <title>On Programming Language Design</title>
    <link href="https://blog.ielliott.io/on-programming-language-design" />
    
    <id>https://blog.ielliott.io/on-programming-language-design</id>
    
    <published>2018-11-21T00:00:00Z</published>
    <updated>2018-11-21T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/on-programming-language-design"><![CDATA[<p>In his <a href="https://www.youtube.com/watch?v=IOiZatlZtGU">propositions as types
talk</a>, Philip Wadler contrasts
programming languages that have been ‘invented’ with those that have been
‘discovered’. <a href="https://www.youtube.com/watch?v=IOiZatlZtGU&amp;t=28m12s">“And you can tell!” he exclaims, receiving giggles from the
audience</a>. Regardless of
how you feel about <a href="https://en.wikipedia.org/wiki/Philosophy_of_mathematics#Platonism">mathematical
platonism</a>,
I think Phil is pointing at a meaningful difference in the way certain ideas
arise.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/on-programming-language-design"><![CDATA[
      
      <p>In his <a href="https://www.youtube.com/watch?v=IOiZatlZtGU">propositions as types
talk</a>, Philip Wadler contrasts
programming languages that have been ‘invented’ with those that have been
‘discovered’. <a href="https://www.youtube.com/watch?v=IOiZatlZtGU&amp;t=28m12s">“And you can tell!” he exclaims, receiving giggles from the
audience</a>. Regardless of
how you feel about <a href="https://en.wikipedia.org/wiki/Philosophy_of_mathematics#Platonism">mathematical
platonism</a>,
I think Phil is pointing at a meaningful difference in the way certain ideas
arise.</p>
<hr />
<p><a href="https://en.wikipedia.org/wiki/Vacuum_cleaner">Vacuum cleaner</a> is just not ‘the
same kind of thing’ as <a href="https://en.wikipedia.org/wiki/Monoid">monoid</a>.</p>
<p>On one hand, we have something that was built to accomplish a task. Vacuum cleaners
suck stuff up. Some of them have wheels and some go on your back. Some have
carpet cleaning attachments and some are adapted for tile floors. In the end, we
have an object that was made to clean, made of bits that we can point to and say
“this bit helps it suck better” or “this bit makes it easier to move” or “this
bit makes it look pretty”.</p>
<p>On the other hand, we have something that describes how things can relate to
each other. When you say “the natural numbers with addition and 0 form a
monoid”, you impose some structure onto the natural numbers. We can prove
whether or not the naturals do exhibit this structure, and then use that fact to
inform how we should think about them. We can’t ‘point at bits of monoid’ and
say how much they contribute to some purpose.</p>
<p>It seems like the popular perception of programming languages falls more in the
‘vacuum cleaner’ camp: that a programming language is <em>just</em> something for
translating a description of computation into something machine-readable. If you
want to describe computations involving numbers and strings, then you add ‘do
number stuff’ and ‘do string stuff’ features to the language. If you find that
‘X-Y-Z’ is a common coding pattern, you might introduce ‘W’ syntax, which does
‘X-Y-Z’ but is easier to type.</p>
<p>I think that this ‘features focused’ development style can cause people to
ignore too much of the structure that the features contribute to
(or even that the features are <em>destroying</em> structure).
Programming language ‘design’ needs a lot of what goes in the ‘monoid’ camp. That
is, they should be treated as more of an abstract thing that gives some
structure to computation. Ignoring this aspect of development is what leads to
edge cases, unintuitive behaviour, and this general feeling of ‘poor design’.</p>
<p>How many people have been surprised to learn that <a href="http://www.walkingrandomly.com/?p=5380">floating point addition is not
associative</a>? It seems reasonable to
just expect addition to be associative. Many programming language
<a href="https://www.destroyallsoftware.com/talks/wat">‘wats’</a> exist for a similar
reason - they are examples of a language behaving counter to our expectations.
In both these cases there are implicit ‘structural contracts’ that are violated.
Hidden patterns about how things relate to each other that are so common we just take
them for granted, but are not present in certain systems by design.</p>
<p>So I think a big part of what makes a language feel ‘discovered’ as opposed to
‘invented’ is the amount of attention paid to the structure of the thing.
‘Discovered’-seeming languages have more internal consistency and fewer
‘quirks’, because they’re not meant to <em>just</em> ‘turn descriptions of computations
into binary’. They have to do this in a way that adheres to a consistent,
coherent structure of computation.</p>
    ]]></content>
    
</entry>
<entry>
    <title>Turning bottom-up into top-down with Reverse State</title>
    <link href="https://blog.ielliott.io/topsy-turvy-reverse-state" />
    
    <id>https://blog.ielliott.io/topsy-turvy-reverse-state</id>
    
    <published>2018-06-13T00:00:00Z</published>
    <updated>2018-06-13T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/topsy-turvy-reverse-state"><![CDATA[<p>I love <a href="https://hackage.haskell.org/package/bound">bound</a> - it makes <a href="https://en.wikipedia.org/wiki/De_Bruijn_index">De
Bruijn indices</a> mindlessly easy. I also love
<a href="https://hackage.haskell.org/package/lens/docs/Control-Lens-Plated.html">Plated</a>
for all sorts of whole-program transformations. I think they’re two
indispensible tools for working with programming languages.
Unfortunately, they’re not compatible.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/topsy-turvy-reverse-state"><![CDATA[
      
      <p>I love <a href="https://hackage.haskell.org/package/bound">bound</a> - it makes <a href="https://en.wikipedia.org/wiki/De_Bruijn_index">De
Bruijn indices</a> mindlessly easy. I also love
<a href="https://hackage.haskell.org/package/lens/docs/Control-Lens-Plated.html">Plated</a>
for all sorts of whole-program transformations. I think they’re two
indispensible tools for working with programming languages.
Unfortunately, they’re not compatible.</p>
<p>The <a href="https://hackage.haskell.org/package/bound/docs/Bound.html#t:Scope">Scope
datatype</a>
in <code>bound</code> is very safe. The type prevents you from creating invalid De
Bruijn terms, like <code>λ. 3</code>. This means that you can’t write useful
instances of <code>Plated</code> for types which contain a <code>Scope</code>. When it comes
to choosing between <code>bound</code> and <code>Plated</code>, I choose <code>Plated</code> - because we
can use it to build functionality similar to <code>bound</code>.</p>
<h2 id="write-some-code"><a href="#write-some-code">Write some code!</a></h2>
<h3 id="warning-the-code-in-this-post-is-subtly-broken-see-the-reddit-thread"><a href="#warning-the-code-in-this-post-is-subtly-broken-see-the-reddit-thread">Warning: the code in this post is subtly broken. See the <span>reddit thread</span></a></h3>
<p>Let’s get some boilerplate out of the road. Here is a datatype for
lambda calculus, with De Bruijn indices (<code>B</code>), as well as free variables
(<code>F</code>). Notice that lambda abstraction (<code>Abs</code>) doesn’t give a name to the
function argument, which means that only <code>B</code>s can reference them. This
is called the “locally nameless” approach.</p>
<p><a href="../files/reverse-state.lhs">Literate Haskell source</a></p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# language DeriveGeneric #-}</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Lens.Plated</span> (<span class="dt">Plated</span>(..), gplate, transformM)</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">GHC.Generics</span> (<span class="dt">Generic</span>)</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Control.Monad.RevState</span> <span class="kw">as</span> <span class="dt">Reverse</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Control.Monad.State</span> <span class="kw">as</span> <span class="dt">State</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Expr</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">F</span> <span class="dt">String</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">B</span> <span class="dt">Int</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">App</span> <span class="dt">Expr</span> <span class="dt">Expr</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Abs</span> <span class="dt">Expr</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Eq</span>, <span class="dt">Show</span>, <span class="dt">Generic</span>)</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Plated</span> <span class="dt">Expr</span> <span class="kw">where</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>  plate <span class="ot">=</span> gplate</span></code></pre></div>
<p>The core of the <code>bound</code>-like API will be two functions:</p>
<ul>
<li><code>abstract :: String -&gt; Expr -&gt; Expr</code></li>
<li><code>instantiate :: Expr -&gt; Expr -&gt; Maybe Expr</code></li>
</ul>
<p>Let’s do <code>abstract</code> first.</p>
<p><code>abstract name expr</code> finds all the <code>F name</code> nodes in an <code>expr</code> and
replaces them with the appropriate De Bruijn index, then wraps the final
result in an <code>Abs</code>. The “appropriate index” is the number of <code>Abs</code>
constructors that we passed on the way.</p>
<p>For example, <code>abstract "x" (F "x")</code> evaluates to <code>Abs (B 0)</code>, because we
passed zero <code>Abs</code> constructors to get to the <code>"x"</code>, then wrapped the final
result in an <code>Abs</code>. <code>abstract "y" (Abs (App (B 0) (F "y")))</code> evaluates to
<code>Abs (Abs (App (B 0) (B 1)))</code> because we passed one <code>Abs</code> to get to the
<code>"y"</code>, then wrapped the final result in an <code>Abs</code>.</p>
<p>“Do this everywhere” usually means
<a href="https://hackage.haskell.org/package/lens/docs/Control-Lens-Plated.html#v:transform">transform</a> <code>:: Plated a =&gt; (a -&gt; a) -&gt; a -&gt; a</code> is appropriate. Though
in this case, it doesn’t give us any way to count the number of <code>Abs</code> it
passes. Instead we will use <a href="https://hackage.haskell.org/package/lens/docs/Control-Lens-Plated.html#v:transformM">transformM</a> <code>:: (Monad m, Plated a) =&gt; (a -&gt; m a) -&gt; a -&gt; m a</code>
with <a href="https://hackage.haskell.org/package/mtl/docs/Control-Monad-State.html">State</a>.</p>
<p>Here’s how that looks:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ot">abstract_attempt_1 ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Expr</span> <span class="ot">-&gt;</span> <span class="dt">Expr</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>abstract_attempt_1 name <span class="ot">=</span> <span class="dt">Abs</span> <span class="op">.</span> <span class="fu">flip</span> State.evalState <span class="dv">0</span> <span class="op">.</span> transformM fun</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="ot">    fun ::</span> <span class="dt">Expr</span> <span class="ot">-&gt;</span> <span class="dt">State.State</span> <span class="dt">Int</span> <span class="dt">Expr</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    fun (<span class="dt">F</span> name&#39;)</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>      <span class="op">|</span> name <span class="op">==</span> name&#39; <span class="ot">=</span> <span class="dt">B</span> <span class="op">&lt;$&gt;</span> State.get</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>      <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="fu">pure</span> <span class="op">$</span> <span class="dt">F</span> name&#39;</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>    fun (<span class="dt">Abs</span> expr) <span class="ot">=</span> <span class="dt">Abs</span> expr <span class="op">&lt;$</span> State.modify (<span class="op">+</span><span class="dv">1</span>)</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>    fun expr <span class="ot">=</span> <span class="fu">pure</span> expr</span></code></pre></div>
<p>If you see a free variable with the name we’re abstracting over, replace
it with a De Bruijn index corresponding to the number of binders we’ve
seen. If you see an <code>Abs</code>, increment the counter. If you see something
else, don’t do anything special.</p>
<p>This is the right idea, but it doesn’t work because the <code>transform</code>
family of functions act from the bottom up. When it sees a free variable
it can abstract over, it will replace it with <code>B 0</code>, then go upwards
through the tree, incrementing the counter. This is the <em>reverse</em> of
what we want.</p>
<h2 id="etats"><a href="#etats">etatS</a></h2>
<p>Enter <a href="http://hackage.haskell.org/package/rev-state/docs/Control-Monad-Trans-RevState.html">Reverse
State</a>.
In reverse state, <code>get</code> accesses the state of the computation <em>after</em>
it, not before it. Using regular state,
<code>execState (modify (+1) *&gt; modify (*2)) 0</code> will evaluate to <code>2</code>, because
you set the state to zero, add one, then multiply by two. Using reverse
state, the output is <code>1</code>, because you set the state to zero, multiply by
two, then add one.</p>
<p>This means that if we swap regular state for reverse state in
<code>abstract</code>, <code>get</code> refers to a state which is only calculated <em>after</em>
bubbling all the way to the top, and counting all the <code>Abs</code>
constructors.</p>
<p>So the correct code looks like this:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ot">abstract ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Expr</span> <span class="ot">-&gt;</span> <span class="dt">Expr</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>abstract name <span class="ot">=</span> <span class="dt">Abs</span> <span class="op">.</span> <span class="fu">flip</span> Reverse.evalState <span class="dv">0</span> <span class="op">.</span> transformM fun</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ot">    fun ::</span> <span class="dt">Expr</span> <span class="ot">-&gt;</span> <span class="dt">Reverse.State</span> <span class="dt">Int</span> <span class="dt">Expr</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    fun (<span class="dt">F</span> name&#39;)</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>      <span class="op">|</span> name <span class="op">==</span> name&#39; <span class="ot">=</span> <span class="dt">B</span> <span class="op">&lt;$&gt;</span> Reverse.get</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>      <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="fu">pure</span> <span class="op">$</span> <span class="dt">F</span> name&#39;</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>    fun (<span class="dt">Abs</span> expr) <span class="ot">=</span> <span class="dt">Abs</span> expr <span class="op">&lt;$</span> Reverse.modify (<span class="op">+</span><span class="dv">1</span>)</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>    fun expr <span class="ot">=</span> <span class="fu">pure</span> expr</span></code></pre></div>
<p>The logic remains the same, except now the state transformations run
backwards.</p>
<p>Now for <code>instantiate</code>.</p>
<p><code>instantiate (Abs body) x</code> substitutes <code>x</code> into
the appropriate positions in <code>body</code>, and wraps the final result in a
<code>Just</code>. If the first argument to <code>instantiate</code> is not an <code>Abs</code>, then the
result is <code>Nothing</code>. We substitute <code>x</code> everywhere we find a <code>B</code> that
contains the number of binders we have passed.</p>
<p>For example, <code>instantiate (Abs (B 0)) (F "x")</code> evaluates to
<code>Just (F "x")</code>, because we found a <code>B 0</code> when we had passed zero binders
(the outer <code>Abs</code> doesn’t count).
<code>instantiate (Abs (Abs (App (B 0) (B 1)))) (F "y")</code> evaluates to
<code>Just (Abs (App (B 0) (F "y")))</code>, because we found a <code>B 1</code> when we had
passed one binder. The <code>B 0</code> is not replaced because at that point, we
had passed one binder, and zero is not one.</p>
<p>We have the same problem as with <code>abstract</code>: counting binders proceeds
from the top down, but <code>transformM</code> works from the bottom up. We can use
reverse state again to solve this. Here’s the code:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ot">instantiate ::</span> <span class="dt">Expr</span> <span class="ot">-&gt;</span> <span class="dt">Expr</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> <span class="dt">Expr</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>instantiate (<span class="dt">Abs</span> body) x <span class="ot">=</span> <span class="dt">Just</span> <span class="op">$</span> Reverse.evalState (transformM fun body) <span class="dv">0</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ot">    fun ::</span> <span class="dt">Expr</span> <span class="ot">-&gt;</span> <span class="dt">Reverse.State</span> <span class="dt">Int</span> <span class="dt">Expr</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    fun (<span class="dt">B</span> n) <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>      n&#39; <span class="ot">&lt;-</span> Reverse.get</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>      <span class="fu">pure</span> <span class="op">$</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>        <span class="kw">if</span> n <span class="op">==</span> n&#39;</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>        <span class="kw">then</span> x</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>        <span class="kw">else</span> <span class="dt">B</span> n</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>    fun (<span class="dt">Abs</span> expr) <span class="ot">=</span> <span class="dt">Abs</span> expr <span class="op">&lt;$</span> Reverse.modify (<span class="op">+</span><span class="dv">1</span>)</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>    fun expr <span class="ot">=</span> <span class="fu">pure</span> expr</span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>instantiate _ _ <span class="ot">=</span> <span class="dt">Nothing</span></span></code></pre></div>
<p>And there we have it: a <code>bound</code>-like API for a datatype using <code>Plated</code>.</p>
<p>I think there are two pressing issues when comparing this code to
<code>bound</code>: correctness and generalisation. This approach allows you to
write bogus terms, like <code>Abs (B 3)</code>, whereas <code>bound</code> does not. I’m okay
with this, because I highly value the tools <code>Plated</code> provides.
Additionally, the <code>bound</code> combinators work over any term as long as it
is a <code>Monad</code>, so <code>abstract</code> and <code>instantiate</code> only have to be written
once, whereas we haven’t presented any means for generalisation of the
<code>Plated</code> approach.</p>
<p>This is easily fixed: in a follow-up post, I’ll
write about how we can use Backpacky Prisms to provide <code>abstract</code>
and <code>instantiate</code> as library functions.</p>
    ]]></content>
    
</entry>
<entry>
    <title>Comonad Transformers in the Wild</title>
    <link href="https://blog.ielliott.io/comonad-transformers-in-the-wild" />
    
    <id>https://blog.ielliott.io/comonad-transformers-in-the-wild</id>
    
    <published>2018-02-25T00:00:00Z</published>
    <updated>2018-02-25T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/comonad-transformers-in-the-wild"><![CDATA[<p>A certain algorithmic puzzle website has a problem that goes like this…</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/comonad-transformers-in-the-wild"><![CDATA[
      
      <p>A certain algorithmic puzzle website has a problem that goes like this…</p>
<pre><code>Given a grid of integers, find the largest product of n numbers which are
adjacent in the same direction (left, right, up, down, or diagonally)</code></pre>
<p>In this diagram, <code>A</code>, <code>B</code>, and <code>C</code> are diagonally adjacent:</p>
<pre><code>0 0 0 0
0 0 0 C
0 0 B 0
0 A 0 0 </code></pre>
<p>And in this one, <code>A</code>, <code>B</code>, and <code>C</code> are vertically adjacent:</p>
<pre><code>0 A 0 0
0 B 0 0
0 C 0 0
0 0 0 0 </code></pre>
<p>I initially solved the problem with this data structure and operations:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Grid</span> a</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">Grid</span> </span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  {<span class="ot"> width ::</span> <span class="op">!</span><span class="dt">Int</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> height ::</span> <span class="op">!</span><span class="dt">Int</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> xPos ::</span> <span class="op">!</span><span class="dt">Int</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> yPos ::</span> <span class="op">!</span><span class="dt">Int</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>  ,<span class="ot"> content ::</span> [[a]]</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="ot">focus ::</span> <span class="dt">Grid</span> a <span class="ot">-&gt;</span> a</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>focus (<span class="dt">Grid</span> _ _ x y g) <span class="ot">=</span> (g <span class="op">!!</span> y) <span class="op">!!</span> x</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- These operations return Nothing if we are at the edge of the grid,</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- otherwise increment/decrement xPos/yPos accordingly</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>up, left, down,<span class="ot"> right ::</span> <span class="dt">Grid</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (<span class="dt">Grid</span> a)</span></code></pre></div>
<p>The idea being to walk through the grid, and for each position calculate the product of the adjacent elements. For example, the product of the focus and the two neighbours to its right would be:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ot">example1 ::</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> <span class="dt">Grid</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>example1 grid <span class="ot">=</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  (\b c <span class="ot">-&gt;</span> focus grid <span class="op">*</span> b <span class="op">*</span> c) <span class="op">&lt;$&gt;</span> </span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  <span class="fu">fmap</span> pos (right grid) <span class="op">&lt;*&gt;</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>  <span class="fu">fmap</span> pos (right <span class="op">&lt;=&lt;</span> right <span class="op">$</span> grid)</span></code></pre></div>
<p><code>Grid</code> can be given a <code>Comonad</code> instance, and this process of per-position calulation can be expressed using comonadic operations. If we plug the <code>example1</code> function into <code>extend</code>, we get the function <code>extend example1 :: Grid a -&gt; Grid (Maybe a)</code>. This function walks through the grid, and replaces each cell with the result of running <code>example1</code> on it and its neighbours.</p>
<p>This is cool in and of itself, but implementing <code>duplicate</code> or <code>extend</code> for <code>Grid</code> is tedious. <code>Grid</code> can actually be implemented as the composition of two comonads: <a href="https://hackage.haskell.org/package/comonad/docs/Control-Comonad-Env.html">Env</a> and <a href="https://hackage.haskell.org/package/comonad/docs/Control-Comonad-Store.html">Store</a>, which gives us the correct comonadic behaviour for free.</p>
<hr />
<p><a href="../files/grid_comonad.lhs">Literal Haskell source</a></p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Applicative</span> (liftA2)</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Monad</span> ((&lt;=&lt;))</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Comonad</span> ((=&gt;&gt;), extract)</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Comonad.Env</span> (<span class="dt">EnvT</span>(..), ask)</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Comonad.Store</span> (<span class="dt">Store</span>, store, peek, pos, seek)</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.List</span> (maximum)</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Dimensions</span> <span class="ot">=</span> (<span class="dt">Int</span>, <span class="dt">Int</span>)</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Position</span> <span class="ot">=</span> (<span class="dt">Int</span>, <span class="dt">Int</span>)</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Grid</span> a <span class="ot">=</span> <span class="dt">EnvT</span> <span class="dt">Dimensions</span> (<span class="dt">Store</span> <span class="dt">Position</span>) a</span></code></pre></div>
<p><code>EnvT e w a</code> is an environment of type <code>e</code> paired with an underlying comonad <code>w a</code>. We can inspect the environment with <code>ask :: ComonadEnv e w =&gt; w a -&gt; e</code>. <code>extract</code>ing from an <code>EnvT</code> just extracts from the underlying comonad, and ignores the environment. The dimensions of the grid are the environment because they remain static throughout the program.</p>
<p><code>Store s a</code> consists of some state <code>s</code>, and an “accessor” function of type <code>s -&gt; a</code>. <code>extract</code>ing a <code>Store</code> feeds its state into the accessor function. For <code>Grid</code>, the focus position is the state, and the accessor is a function that pulls out the corresponding element from some list of lists.</p>
<p>Three important functions on <code>Store</code> are:</p>
<ul>
<li><code>pos :: ComonadStore s w =&gt; w a -&gt; s</code></li>
<li><code>seek :: ComonadStore s w =&gt; s -&gt; w a -&gt; w a</code></li>
<li><code>peek :: ComonadStore s w =&gt; s -&gt; w a -&gt; a</code></li>
</ul>
<p><code>pos</code> returns the current state, <code>seek</code> replaces the state, and <code>peek</code> runs the accessor function on a different piece of state, leaving the actual state unchanged.</p>
<p>Here’s how we make a grid. Notice that the accessor function passed to <code>store</code> behaves like <code>focus</code>.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ot">mkGrid ::</span> [[a]] <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (<span class="dt">Grid</span> a)</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>mkGrid [] <span class="ot">=</span> <span class="dt">Nothing</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>mkGrid g<span class="op">@</span>(r<span class="op">:</span>rs)</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> rl <span class="ot">&lt;-</span> <span class="fu">length</span> r</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>  , <span class="fu">all</span> ((<span class="op">==</span>rl) <span class="op">.</span> <span class="fu">length</span>) rs <span class="ot">=</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Just</span> <span class="op">$</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>      <span class="dt">EnvT</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>        (rl, <span class="fu">length</span> g)</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>        (store (\(x, y) <span class="ot">-&gt;</span> (g <span class="op">!!</span> y) <span class="op">!!</span> x) (<span class="dv">0</span>, <span class="dv">0</span>))</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dt">Nothing</span></span></code></pre></div>
<p>If the grid has no rows, or has rows of different lengths, return nothing. Otherwise, calculate the dimensions of the grid, and initialise the store pointing to the top-left cell in the grid.</p>
<p>Now we can implement <code>up, down, left, right</code>:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ot">up ::</span> <span class="dt">Grid</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (<span class="dt">Grid</span> a)</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>up g <span class="ot">=</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>    (w, h) <span class="ot">=</span> ask g</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>    (x, y) <span class="ot">=</span> pos g</span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">in</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">if</span> y <span class="op">&gt;</span> <span class="dv">0</span> <span class="kw">then</span> <span class="dt">Just</span> (seek (x, y<span class="op">-</span><span class="dv">1</span>) g) <span class="kw">else</span> <span class="dt">Nothing</span> </span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="ot">left ::</span> <span class="dt">Grid</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (<span class="dt">Grid</span> a)</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>left g <span class="ot">=</span></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>    (w, h) <span class="ot">=</span> ask g</span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a>    (x, y) <span class="ot">=</span> pos g</span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">in</span></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a>    <span class="kw">if</span> x <span class="op">&gt;</span> <span class="dv">0</span> <span class="kw">then</span> <span class="dt">Just</span> (seek (x<span class="op">-</span><span class="dv">1</span>, y) g) <span class="kw">else</span> <span class="dt">Nothing</span> </span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a><span class="ot">down ::</span> <span class="dt">Grid</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (<span class="dt">Grid</span> a)</span>
<span id="cb8-18"><a href="#cb8-18" aria-hidden="true" tabindex="-1"></a>down g <span class="ot">=</span></span>
<span id="cb8-19"><a href="#cb8-19" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span></span>
<span id="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a>    (w, h) <span class="ot">=</span> ask g</span>
<span id="cb8-21"><a href="#cb8-21" aria-hidden="true" tabindex="-1"></a>    (x, y) <span class="ot">=</span> pos g</span>
<span id="cb8-22"><a href="#cb8-22" aria-hidden="true" tabindex="-1"></a>  <span class="kw">in</span></span>
<span id="cb8-23"><a href="#cb8-23" aria-hidden="true" tabindex="-1"></a>    <span class="kw">if</span> y <span class="op">&lt;</span> h<span class="op">-</span><span class="dv">1</span> <span class="kw">then</span> <span class="dt">Just</span> (seek (x, y<span class="op">+</span><span class="dv">1</span>) g) <span class="kw">else</span> <span class="dt">Nothing</span> </span>
<span id="cb8-24"><a href="#cb8-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-25"><a href="#cb8-25" aria-hidden="true" tabindex="-1"></a><span class="ot">right ::</span> <span class="dt">Grid</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (<span class="dt">Grid</span> a)</span>
<span id="cb8-26"><a href="#cb8-26" aria-hidden="true" tabindex="-1"></a>right g <span class="ot">=</span></span>
<span id="cb8-27"><a href="#cb8-27" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span></span>
<span id="cb8-28"><a href="#cb8-28" aria-hidden="true" tabindex="-1"></a>    (w, h) <span class="ot">=</span> ask g</span>
<span id="cb8-29"><a href="#cb8-29" aria-hidden="true" tabindex="-1"></a>    (x, y) <span class="ot">=</span> pos g</span>
<span id="cb8-30"><a href="#cb8-30" aria-hidden="true" tabindex="-1"></a>  <span class="kw">in</span></span>
<span id="cb8-31"><a href="#cb8-31" aria-hidden="true" tabindex="-1"></a>    <span class="kw">if</span> x <span class="op">&lt;</span> w<span class="op">-</span><span class="dv">1</span> <span class="kw">then</span> <span class="dt">Just</span> (seek (x<span class="op">+</span><span class="dv">1</span>, y) g) <span class="kw">else</span> <span class="dt">Nothing</span> </span></code></pre></div>
<p>Next are some helper functions for calculating the product of a grid element and its neighbours.</p>
<p><code>iterateM</code> is the monadic equivalent of <a href="https://hackage.haskell.org/package/base/docs/Data-List.html#v:iterate">iterate</a>.</p>
<p><code>productN</code> calculates the product of the current grid element with its adjacent neighbours in some direction. <code>example1</code> could be redefined as <code>productN 3 right</code>.</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ot">iterateM ::</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> m a) <span class="ot">-&gt;</span> [a <span class="ot">-&gt;</span> m a]</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>iterateM f <span class="ot">=</span> f <span class="op">:</span> <span class="fu">fmap</span> (f <span class="op">&lt;=&lt;</span>) (iterateM f)</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="ot">productN ::</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> (<span class="dt">Grid</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> (<span class="dt">Grid</span> a)) <span class="ot">-&gt;</span> <span class="dt">Grid</span> a <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>productN n f g <span class="ot">=</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>  <span class="fu">foldr</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>    (\a b <span class="ot">-&gt;</span> liftA2 (<span class="op">*</span>) (extract <span class="op">&lt;$&gt;</span> a g) b)</span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>    (<span class="fu">pure</span> <span class="dv">1</span>)</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a>    (<span class="fu">take</span> n <span class="op">$</span> iterateM f)</span></code></pre></div>
<p>Penultimately, we define a function for finding the greatest element in a grid. It <code>peek</code>s at all the elements and finds the greatest one.</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ot">maxInGrid ::</span> <span class="dt">Ord</span> a <span class="ot">=&gt;</span> <span class="dt">Grid</span> a <span class="ot">-&gt;</span> a</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>maxInGrid g <span class="ot">=</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>    (w, h) <span class="ot">=</span> ask g</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">in</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>    <span class="fu">maximum</span> <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>      x <span class="ot">&lt;-</span> [<span class="dv">0</span><span class="op">..</span>w<span class="op">-</span><span class="dv">1</span>]</span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>      y <span class="ot">&lt;-</span> [<span class="dv">0</span><span class="op">..</span>h<span class="op">-</span><span class="dv">1</span>]</span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>      <span class="fu">pure</span> <span class="op">$</span> peek (x, y) g</span></code></pre></div>
<p>Last step. To find the largest product of <code>n</code> adjacent elements, we find the largest product of <code>n</code> adjacent elements horizontally, then vertically, then diagonally, and take the maximum of those.</p>
<p>We can write this logic as a series of <code>extend</code>s, because <code>productN n move</code> and <code>maxInGrid</code> are both of the form <code>w a -&gt; b</code>. (<code>(=&gt;&gt;)</code> is the flipped infix version of <code>extend</code>)</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="ot">largestProduct ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Grid</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>largestProduct n g <span class="ot">=</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">let</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Just</span> g1 <span class="ot">=</span> extract <span class="op">$</span> g <span class="op">=&gt;&gt;</span> productN n right            <span class="op">=&gt;&gt;</span> maxInGrid</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Just</span> g2 <span class="ot">=</span> extract <span class="op">$</span> g <span class="op">=&gt;&gt;</span> productN n down             <span class="op">=&gt;&gt;</span> maxInGrid</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Just</span> g3 <span class="ot">=</span> extract <span class="op">$</span> g <span class="op">=&gt;&gt;</span> productN n (down <span class="op">&lt;=&lt;</span> left)  <span class="op">=&gt;&gt;</span> maxInGrid</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Just</span> g4 <span class="ot">=</span> extract <span class="op">$</span> g <span class="op">=&gt;&gt;</span> productN n (down <span class="op">&lt;=&lt;</span> right) <span class="op">=&gt;&gt;</span> maxInGrid</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">in</span></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>    <span class="fu">maximum</span> [g1, g2, g3, g4]</span></code></pre></div>
<p>I’m still getting an intuition for comonads, but they seem to embody some kind of “environment”, and comonad transformers are like a “composition of environments”. In this example, there are two environments: the grid’s dimensions, and its content.</p>
<p>For more information about comonads, check out Bartosz Milewski’s <a href="https://bartoszmilewski.com/2017/01/02/comonads/">comonads post</a> and Dan Piponi’s article about <a href="http://blog.sigfpe.com/2006/12/evaluating-cellular-automata-is.html">comonadic cellular automata</a>.</p>
<p>Footnote: I feel like <code>largestProduct</code> could be simplified if <code>Grid</code> were <code>ComonadApply</code>, but I haven’t tried to figure it out yet.</p>
    ]]></content>
    
</entry>
<entry>
    <title>Continuations From the Ground Up</title>
    <link href="https://blog.ielliott.io/continuations-from-the-ground-up" />
    
    <id>https://blog.ielliott.io/continuations-from-the-ground-up</id>
    
    <published>2017-06-06T00:00:00Z</published>
    <updated>2017-06-06T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/continuations-from-the-ground-up"><![CDATA[<p>It’s difficult to learn functional programming without hearing about continuations. Often they’re mentioned while talking about boosting the performance of pure functional code, sometimes there’s talk of control flow, and occasionally with ‘time-travel’ thrown in there to make it all seem more obscure. It’s all true, but let’s start from the beginning.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/continuations-from-the-ground-up"><![CDATA[
      
      <p>It’s difficult to learn functional programming without hearing about continuations. Often they’re mentioned while talking about boosting the performance of pure functional code, sometimes there’s talk of control flow, and occasionally with ‘time-travel’ thrown in there to make it all seem more obscure. It’s all true, but let’s start from the beginning.</p>
<p>This post was generated from a <a href="../files/continuations.lhs">Literate Haskell file</a> using Pandoc, so you can load it up into GHCI and play around if you want.</p>
<h2 id="continuation-passing-style"><a href="#continuation-passing-style">Continuation Passing Style</a></h2>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">CPS</span> <span class="kw">where</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Applicative</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Monad.Trans.Class</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.IORef</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Maybe</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Map</span> <span class="kw">as</span> <span class="dt">M</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">System.Exit</span> <span class="kw">as</span> <span class="dt">E</span></span></code></pre></div>
<p>The main idea of this style is that the called function has control over how its return value is used. Usually, the caller will pass a function that tells the callee how to use its return value. Here’s what that looks like:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ot">add ::</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> r) <span class="ot">-&gt;</span> r</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>add a b <span class="ot">=</span> \k <span class="ot">-&gt;</span> k (a <span class="op">+</span> b)</span></code></pre></div>
<p><code>add</code> takes two numbers, plus a function that will take the result and do something (returning an unknown answer), then pass the result to this function. We call this ‘extra function’ a <em>continuation</em> because it specifies how the program should <em>continue</em>.</p>
<p>It’s possible to write any program using this style. I’m not going to prove it. As a challenge, let’s restrict ourselves to write every function this way, with two exceptions:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ot">exitSuccess ::</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>exitSuccess _ <span class="ot">=</span> E.exitSuccess</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ot">exitFailure ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>exitFailure <span class="ot">=</span> E.exitWith <span class="op">.</span> <span class="dt">E.ExitFailure</span></span></code></pre></div>
<p><code>exitSuccess</code> and <code>exitFailure</code> do not take a continuation, because the program always ends when they are called.</p>
<p>Let’s define <code>mul</code> and <code>dvd</code>:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ot">mul ::</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> r) <span class="ot">-&gt;</span> r</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>mul a b <span class="ot">=</span> \k <span class="ot">-&gt;</span> k (a <span class="op">*</span> b)</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ot">dvd ::</span> <span class="dt">Fractional</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> r) <span class="ot">-&gt;</span> r</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>dvd a b <span class="ot">=</span> \k <span class="ot">-&gt;</span> k (a <span class="op">/</span> b)</span></code></pre></div>
<p>Now we can write some programs using this style.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Exits with status code 5</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="ot">prog_1 ::</span> <span class="dt">IO</span> ()</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>prog_1 <span class="ot">=</span> add <span class="dv">2</span> <span class="dv">3</span> exitFailure</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- Exits successfully after multiplying 10 by 10</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="ot">prog_2 ::</span> <span class="dt">IO</span> ()</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>prog_2 <span class="ot">=</span> mul <span class="dv">10</span> <span class="dv">10</span> exitSuccess</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- Exits with status code (2 + 3) * 5 = 25</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="ot">prog_3 ::</span> <span class="dt">IO</span> ()</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>prog_3 <span class="ot">=</span> add <span class="dv">2</span> <span class="dv">3</span> (\two_plus_three <span class="ot">-&gt;</span> mul two_plus_three <span class="dv">5</span> exitFailure)</span></code></pre></div>
<p>We can factor out the continuation to make our program more modular:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Equivalent to \k -&gt; k ((2 + 3) * 5)</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="ot">prog_4 ::</span> (<span class="dt">Int</span> <span class="ot">-&gt;</span> r) <span class="ot">-&gt;</span> r</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>prog_4 <span class="ot">=</span> \k <span class="ot">-&gt;</span> add <span class="dv">2</span> <span class="dv">3</span> (\two_plus_three <span class="ot">-&gt;</span> mul two_plus_three <span class="dv">5</span> k)</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- Equivalent to \k -&gt; k ((2 + 3) * 5 + 5)</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="ot">prog_5 ::</span> (<span class="dt">Int</span> <span class="ot">-&gt;</span> r) <span class="ot">-&gt;</span> r</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>prog_5 <span class="ot">=</span> \k <span class="ot">-&gt;</span> prog_4 (\res <span class="ot">-&gt;</span> add res <span class="dv">5</span> k)</span></code></pre></div>
<p>In these kind of definitions, we’ll call the <code>k</code> the <em>current continuation</em> to stand for <em>how the program will (currently) continue execution</em>.</p>
<p>Here’s a more complex expression:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- (2 + 3) * (7 + 9) + 5</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="ot">prog_6 ::</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> (a <span class="ot">-&gt;</span> r) <span class="ot">-&gt;</span> r</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>prog_6 <span class="ot">=</span> \k <span class="ot">-&gt;</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>  add <span class="dv">2</span> <span class="dv">3</span> (\five <span class="ot">-&gt;</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>    add <span class="dv">7</span> <span class="dv">9</span> (\sixteen <span class="ot">-&gt;</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>      mul five sixteen (\eighty <span class="ot">-&gt;</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>        add eighty <span class="dv">5</span> k)))</span></code></pre></div>
<p>In translating programs to continuation passing style, we transform a <em>tree</em> of computations into a <em>sequence</em> of computations. In doing so, we have <em>reified</em> the flow of the program. We now have a data structure in memory that represents the computations that make up the program. In this case, the data structure is a lot like a linked list- there is a head: ‘the computation that will be performed next’, and a tail: ‘the computations that will be performed on the result’. It’s this ability to represent the flow of the program as a data structure that sets CPS programs apart from regular programs, which we will see later.</p>
<h2 id="continuation-passing-is-monadic"><a href="#continuation-passing-is-monadic">Continuation Passing is Monadic</a></h2>
<p>Right now, writing CPS programs in Haskell is too verbose. Fortunately there are some familiar abstractions that will make it elegant:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Cont</span> r a <span class="ot">=</span> <span class="dt">Cont</span> {<span class="ot"> runCont ::</span> (a <span class="ot">-&gt;</span> r) <span class="ot">-&gt;</span> r }</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="ot">add&#39; ::</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Cont</span> r a</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>add&#39; a b <span class="ot">=</span> <span class="dt">Cont</span> <span class="op">$</span> add a b</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="ot">mul&#39; ::</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Cont</span> r a</span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>mul&#39; a b <span class="ot">=</span> <span class="dt">Cont</span> <span class="op">$</span> mul a b</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="ot">dvd&#39; ::</span> <span class="dt">Num</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Cont</span> r a</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>dvd&#39; a b <span class="ot">=</span> <span class="dt">Cont</span> <span class="op">$</span> dvd a b</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Functor</span> (<span class="dt">Cont</span> r) <span class="kw">where</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a>  <span class="fu">fmap</span> f c <span class="ot">=</span> <span class="dt">Cont</span> <span class="op">$</span> \k <span class="ot">-&gt;</span> runCont c (k <span class="op">.</span> f)</span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Applicative</span> (<span class="dt">Cont</span> r) <span class="kw">where</span></span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pure</span> a <span class="ot">=</span> <span class="dt">Cont</span> (<span class="op">$</span> a)</span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a>  cf <span class="op">&lt;*&gt;</span> ca <span class="ot">=</span> <span class="dt">Cont</span> <span class="op">$</span> \k <span class="ot">-&gt;</span> runCont cf (\f <span class="ot">-&gt;</span> runCont ca (\a <span class="ot">-&gt;</span> k (f a)))</span>
<span id="cb8-18"><a href="#cb8-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-19"><a href="#cb8-19" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Monad</span> (<span class="dt">Cont</span> r) <span class="kw">where</span></span>
<span id="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a>  ca <span class="op">&gt;&gt;=</span> f <span class="ot">=</span> <span class="dt">Cont</span> <span class="op">$</span> \k <span class="ot">-&gt;</span> runCont ca (\a <span class="ot">-&gt;</span> runCont (f a) k)</span></code></pre></div>
<p>It turns out that the return type of these CPS programs, <code>(a -&gt; r) -&gt; r</code>, is a Monad. If you don’t understand these implementations, meditate on them until you do. Here some hand-wave-y English explanations that may help:</p>
<h3 id="functor"><a href="#functor">Functor</a></h3>
<p><code>fmap</code>: Continue with the result of <code>c</code> by changing the result from an <code>a</code> to a <code>b</code> then sending that result to the current continuation.</p>
<h3 id="applicative"><a href="#applicative">Applicative</a></h3>
<p><code>pure</code>: Send an <code>a</code> to the current continuation</p>
<p><code>&lt;*&gt;</code>: Continue with the result of <code>cf</code> by continuing with the result of <code>ca</code> by sending (the result of <code>cf</code>) applied to (the result of <code>ca</code>) to the current continuation.</p>
<h3 id="monad"><a href="#monad">Monad</a></h3>
<p><code>&gt;&gt;=</code>: Continue with the result of <code>ca</code> by applying it to <code>f</code> and passing the current continuation on to the value <code>f</code> returned.</p>
<p>So now we can rewrite our previous verbose example:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ot">prog_6&#39; ::</span> <span class="dt">Cont</span> r <span class="dt">Int</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>prog_6&#39; <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  five <span class="ot">&lt;-</span> add&#39; <span class="dv">2</span> <span class="dv">3</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>  sixteen <span class="ot">&lt;-</span> add&#39; <span class="dv">7</span> <span class="dv">9</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>  eighty <span class="ot">&lt;-</span> mul&#39; five sixteen</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>  add&#39; eighty <span class="dv">5</span></span></code></pre></div>
<p>and run it:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ot">prog_7 ::</span> <span class="dt">IO</span> ()</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>prog_7 <span class="ot">=</span> runCont prog_6&#39; exitSuccess</span></code></pre></div>
<h2 id="callcc"><a href="#callcc">callCC</a></h2>
<p>Consider the following CPS program:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="ot">prog_8 ::</span> (<span class="dt">Eq</span> a, <span class="dt">Fractional</span> a) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> (<span class="dt">Maybe</span> a <span class="ot">-&gt;</span> r) <span class="ot">-&gt;</span> r</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>prog_8 a b c <span class="ot">=</span> \k <span class="ot">-&gt;</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  add b c</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>    (\b_plus_c <span class="ot">-&gt;</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>      <span class="kw">if</span> b_plus_c <span class="op">==</span> <span class="dv">0</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>        <span class="kw">then</span> k <span class="dt">Nothing</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>        <span class="kw">else</span> dvd a b_plus_c (k <span class="op">.</span> <span class="dt">Just</span>))</span></code></pre></div>
<p>It adds <code>b</code> to <code>c</code>, then if <code>b + c</code> is zero, sends <code>Nothing</code> to the current continuation, otherwise divides <code>a</code> by <code>b + c</code> then continues by wrapping that in a <code>Just</code> and sending the <code>Just</code> result to the current continuation.</p>
<p>Because the current continuation is ‘how the program will continue with the result of this function’, sending a result to the current continuation early cause the function to <em>exit early</em>. In this sense, it’s a bit like like a <code>jmp</code> or a <code>goto</code>.</p>
<p>It is conceivable that somehow we can write a program like this using the <code>Cont</code> monad. This is where <code>callCC</code> comes in.</p>
<p><code>callCC</code> stands for ‘call with current continuation’, and is the way we’re going to bring the current continuation into scope when writing CPS programs. Here’s an example of how the previous code snippet should look using <code>callCC</code>:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ot">prog_8&#39; ::</span> (<span class="dt">Eq</span> a, <span class="dt">Fractional</span> a) <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Cont</span> r (<span class="dt">Maybe</span> a)</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>prog_8&#39; a b c <span class="ot">=</span> callCC <span class="op">$</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>  \k <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    b_plus_c <span class="ot">&lt;-</span> add&#39; b c</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">if</span> b_plus_c <span class="op">==</span> <span class="dv">0</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>      <span class="kw">then</span> k <span class="dt">Nothing</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>      <span class="kw">else</span> <span class="fu">fmap</span> <span class="dt">Just</span> <span class="op">$</span> dvd&#39; a b_plus_c</span></code></pre></div>
<p>Here’s how <code>callCC</code> is defined:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="ot">callCC ::</span> ((a <span class="ot">-&gt;</span> <span class="dt">Cont</span> r b) <span class="ot">-&gt;</span> <span class="dt">Cont</span> r a) <span class="ot">-&gt;</span> <span class="dt">Cont</span> r a</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>callCC f <span class="ot">=</span> <span class="dt">Cont</span> <span class="op">$</span> \k <span class="ot">-&gt;</span> runCont (f (\a <span class="ot">-&gt;</span> <span class="dt">Cont</span> <span class="op">$</span> <span class="fu">const</span> (k a))) k</span></code></pre></div>
<p>We can see that the current continuation is permanently captured when it is used in the function passed to <code>f</code>, but it is also used when running the final result of <code>f</code>. So <code>k</code> might be called somewhere inside <code>f</code>, causing <code>f</code> to exit early, or it might not, in which case <code>k</code> is guaranteed to be called after <code>f</code> has finished.</p>
<p>Earlier I said that invoking the current continuation earlier is like jumping. This is a lot easier to show now that we can use it in our <code>Cont</code> monad. Calling the continuation provided by <code>callCC</code> will jump the program execution to immediately after the call to <code>callCC</code>, and set the result of the <code>callCC</code> continuation to the argument that was passed to the current continuation.</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>prog_9 <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>  five <span class="ot">&lt;-</span> add&#39; <span class="dv">2</span> <span class="dv">3</span> </span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>  res <span class="ot">&lt;-</span> callCC <span class="op">$</span> \k <span class="ot">-&gt;</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- current continuation is never used, so `callCC` is redundant</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>    mul&#39; <span class="dv">4</span> <span class="dv">5</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- `res` = 20</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>  add&#39; five res</span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a>prog_10 <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a>  five <span class="ot">&lt;-</span> add&#39; <span class="dv">2</span> <span class="dv">3</span> </span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a>  res <span class="ot">&lt;-</span> callCC <span class="op">$</span> \k <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a>    k <span class="dv">5</span></span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a>    mul&#39; <span class="dv">4</span> <span class="dv">5</span> <span class="co">-- this computation is never run</span></span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- program jumps to here, `res` = 5</span></span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a>  add&#39; five res</span>
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-17"><a href="#cb14-17" aria-hidden="true" tabindex="-1"></a>prog_11 <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb14-18"><a href="#cb14-18" aria-hidden="true" tabindex="-1"></a>  five <span class="ot">&lt;-</span> add&#39; <span class="dv">2</span> <span class="dv">3</span> </span>
<span id="cb14-19"><a href="#cb14-19" aria-hidden="true" tabindex="-1"></a>  res <span class="ot">&lt;-</span> callCC <span class="op">$</span> \k <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb14-20"><a href="#cb14-20" aria-hidden="true" tabindex="-1"></a>    <span class="kw">if</span> five <span class="op">&gt;</span> <span class="dv">10</span></span>
<span id="cb14-21"><a href="#cb14-21" aria-hidden="true" tabindex="-1"></a>      <span class="kw">then</span> k <span class="dv">10</span> <span class="co">-- branch A</span></span>
<span id="cb14-22"><a href="#cb14-22" aria-hidden="true" tabindex="-1"></a>      <span class="kw">else</span> mul&#39; <span class="dv">4</span> <span class="dv">5</span> <span class="co">-- branch B</span></span>
<span id="cb14-23"><a href="#cb14-23" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- if branch A was reached, `res` = 10</span></span>
<span id="cb14-24"><a href="#cb14-24" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- if branch B was reached, `res` = 20</span></span>
<span id="cb14-25"><a href="#cb14-25" aria-hidden="true" tabindex="-1"></a>  add&#39; five res</span></code></pre></div>
<h2 id="another-level-of-abstraction"><a href="#another-level-of-abstraction">Another level of abstraction</a></h2>
<p>We can also embed arbitrary effects in the return type of <code>Cont</code>. In other words, we can create a monad transformer.</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">ContT</span> r m a <span class="ot">=</span> <span class="dt">ContT</span> {<span class="ot"> runContT ::</span> (a <span class="ot">-&gt;</span> m r) <span class="ot">-&gt;</span> m r }</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="ot">callCC&#39; ::</span> ((a <span class="ot">-&gt;</span> <span class="dt">ContT</span> r m b) <span class="ot">-&gt;</span> <span class="dt">ContT</span> r m a) <span class="ot">-&gt;</span> <span class="dt">ContT</span> r m a</span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>callCC&#39; f <span class="ot">=</span> <span class="dt">ContT</span> <span class="op">$</span> \k <span class="ot">-&gt;</span> runContT (f (\a <span class="ot">-&gt;</span> <span class="dt">ContT</span> <span class="op">$</span> <span class="fu">const</span> (k a))) k</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Functor</span> (<span class="dt">ContT</span> r m) <span class="kw">where</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>  <span class="fu">fmap</span> f c <span class="ot">=</span> <span class="dt">ContT</span> <span class="op">$</span> \k <span class="ot">-&gt;</span> runContT c (k <span class="op">.</span> f)</span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Applicative</span> (<span class="dt">ContT</span> r m) <span class="kw">where</span></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a>  <span class="fu">pure</span> a <span class="ot">=</span> <span class="dt">ContT</span> (<span class="op">$</span> a)</span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a>  cf <span class="op">&lt;*&gt;</span> ca <span class="ot">=</span> <span class="dt">ContT</span> <span class="op">$</span> \k <span class="ot">-&gt;</span> runContT cf (\f <span class="ot">-&gt;</span> runContT ca (\a <span class="ot">-&gt;</span> k (f a)))</span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Monad</span> (<span class="dt">ContT</span> r m) <span class="kw">where</span></span>
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a>  ca <span class="op">&gt;&gt;=</span> f <span class="ot">=</span> <span class="dt">ContT</span> <span class="op">$</span> \k <span class="ot">-&gt;</span> runContT ca (\a <span class="ot">-&gt;</span> runContT (f a) k)</span>
<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-16"><a href="#cb15-16" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">MonadTrans</span> (<span class="dt">ContT</span> r) <span class="kw">where</span></span>
<span id="cb15-17"><a href="#cb15-17" aria-hidden="true" tabindex="-1"></a>  lift ma <span class="ot">=</span> <span class="dt">ContT</span> <span class="op">$</span> \k <span class="ot">-&gt;</span> ma <span class="op">&gt;&gt;=</span> k</span></code></pre></div>
<p>Notice that the <code>Functor</code>, <code>Applicative</code> and <code>Monad</code> instances for <code>ContT r m</code> don’t place any constraints on the <code>m</code>. This means that any type constructor of kind <code>(* -&gt; *)</code> can be in the <code>m</code> position. The <code>MonadTrans</code> instance, however, does require <code>m</code> is a monad. It’s a very simple definition- the result of running the lifted action is piped into the current continuation using <code>&gt;&gt;=</code>.</p>
<p>Now that we have a fully-featured CPS monad, we can start doing magic.</p>
<h2 id="the-future-the-past-and-alternate-timelines"><a href="#the-future-the-past-and-alternate-timelines">The future, the past and alternate timelines</a></h2>
<p>The continuation that <code>callCC</code> provides access to is the current future of program execution as a single function. That’s why this program-as-a-linear-sequence is so powerful. If you could save the current continuation and call it at a later time somewhere else in your (CPS) program, it would jump ‘back in time’ to the point after that particular <code>callCC</code>.</p>
<p>To demonstrate this, and end with a bang, here’s a simple boolean SAT solver.</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Language of boolean expressions</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Expr</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>  <span class="ot">=</span> <span class="dt">Implies</span> <span class="dt">Expr</span> <span class="dt">Expr</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Iff</span> <span class="dt">Expr</span> <span class="dt">Expr</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">And</span> <span class="dt">Expr</span> <span class="dt">Expr</span></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Or</span> <span class="dt">Expr</span> <span class="dt">Expr</span></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Not</span> <span class="dt">Expr</span></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Val</span> <span class="dt">Bool</span></span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a>  <span class="op">|</span> <span class="dt">Var</span> <span class="dt">String</span></span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">deriving</span> (<span class="dt">Eq</span>, <span class="dt">Show</span>)</span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a><span class="co">-- Reduces a boolean expression to normal form, substituting variables</span></span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- where possible. There are also some equivalences that are necessary to get</span></span>
<span id="cb16-14"><a href="#cb16-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- the SAT solver working e.g. Not (Not x) = x (I said it was a simple one!)</span></span>
<span id="cb16-15"><a href="#cb16-15" aria-hidden="true" tabindex="-1"></a>eval</span>
<span id="cb16-16"><a href="#cb16-16" aria-hidden="true" tabindex="-1"></a><span class="ot">  ::</span> <span class="dt">M.Map</span> <span class="dt">String</span> <span class="dt">Expr</span> <span class="co">-- ^ Bound variables</span></span>
<span id="cb16-17"><a href="#cb16-17" aria-hidden="true" tabindex="-1"></a>  <span class="ot">-&gt;</span> <span class="dt">Expr</span> <span class="co">-- ^ Input expression</span></span>
<span id="cb16-18"><a href="#cb16-18" aria-hidden="true" tabindex="-1"></a>  <span class="ot">-&gt;</span> <span class="dt">Expr</span></span>
<span id="cb16-19"><a href="#cb16-19" aria-hidden="true" tabindex="-1"></a>eval env expr <span class="ot">=</span></span>
<span id="cb16-20"><a href="#cb16-20" aria-hidden="true" tabindex="-1"></a>  <span class="kw">case</span> expr <span class="kw">of</span></span>
<span id="cb16-21"><a href="#cb16-21" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Implies</span> p q <span class="ot">-&gt;</span> eval env <span class="op">$</span> <span class="dt">Or</span> (<span class="dt">Not</span> p) q</span>
<span id="cb16-22"><a href="#cb16-22" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Iff</span> p q <span class="ot">-&gt;</span> eval env <span class="op">$</span> <span class="dt">Or</span> (<span class="dt">And</span> p q) (<span class="dt">And</span> (<span class="dt">Not</span> p) (<span class="dt">Not</span> q))</span>
<span id="cb16-23"><a href="#cb16-23" aria-hidden="true" tabindex="-1"></a>    <span class="dt">And</span> a b <span class="ot">-&gt;</span></span>
<span id="cb16-24"><a href="#cb16-24" aria-hidden="true" tabindex="-1"></a>      <span class="kw">case</span> (eval env a, eval env b) <span class="kw">of</span></span>
<span id="cb16-25"><a href="#cb16-25" aria-hidden="true" tabindex="-1"></a>        (<span class="dt">Val</span> <span class="dt">False</span>, _) <span class="ot">-&gt;</span> <span class="dt">Val</span> <span class="dt">False</span></span>
<span id="cb16-26"><a href="#cb16-26" aria-hidden="true" tabindex="-1"></a>        (_, <span class="dt">Val</span> <span class="dt">False</span>) <span class="ot">-&gt;</span> <span class="dt">Val</span> <span class="dt">False</span></span>
<span id="cb16-27"><a href="#cb16-27" aria-hidden="true" tabindex="-1"></a>        (<span class="dt">Val</span> <span class="dt">True</span>, b&#39;) <span class="ot">-&gt;</span> b&#39;</span>
<span id="cb16-28"><a href="#cb16-28" aria-hidden="true" tabindex="-1"></a>        (a&#39;, <span class="dt">Val</span> <span class="dt">True</span>) <span class="ot">-&gt;</span> a&#39;</span>
<span id="cb16-29"><a href="#cb16-29" aria-hidden="true" tabindex="-1"></a>        (a&#39;, b&#39;) <span class="ot">-&gt;</span> <span class="dt">And</span> a&#39; b&#39;</span>
<span id="cb16-30"><a href="#cb16-30" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Or</span> a b <span class="ot">-&gt;</span></span>
<span id="cb16-31"><a href="#cb16-31" aria-hidden="true" tabindex="-1"></a>      <span class="kw">case</span> (eval env a, eval env b) <span class="kw">of</span></span>
<span id="cb16-32"><a href="#cb16-32" aria-hidden="true" tabindex="-1"></a>        (<span class="dt">Val</span> <span class="dt">True</span>, _) <span class="ot">-&gt;</span> <span class="dt">Val</span> <span class="dt">True</span></span>
<span id="cb16-33"><a href="#cb16-33" aria-hidden="true" tabindex="-1"></a>        (_, <span class="dt">Val</span> <span class="dt">True</span>) <span class="ot">-&gt;</span> <span class="dt">Val</span> <span class="dt">True</span></span>
<span id="cb16-34"><a href="#cb16-34" aria-hidden="true" tabindex="-1"></a>        (<span class="dt">Val</span> <span class="dt">False</span>, b&#39;) <span class="ot">-&gt;</span> b&#39;</span>
<span id="cb16-35"><a href="#cb16-35" aria-hidden="true" tabindex="-1"></a>        (a&#39;, <span class="dt">Val</span> <span class="dt">False</span>) <span class="ot">-&gt;</span> a&#39;</span>
<span id="cb16-36"><a href="#cb16-36" aria-hidden="true" tabindex="-1"></a>        (a&#39;, b&#39;)</span>
<span id="cb16-37"><a href="#cb16-37" aria-hidden="true" tabindex="-1"></a>          <span class="op">|</span> a&#39; <span class="op">==</span> eval env (<span class="dt">Not</span> b&#39;) <span class="ot">-&gt;</span> <span class="dt">Val</span> <span class="dt">True</span></span>
<span id="cb16-38"><a href="#cb16-38" aria-hidden="true" tabindex="-1"></a>          <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">-&gt;</span> <span class="dt">Or</span> a&#39; b&#39;</span>
<span id="cb16-39"><a href="#cb16-39" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Not</span> a <span class="ot">-&gt;</span></span>
<span id="cb16-40"><a href="#cb16-40" aria-hidden="true" tabindex="-1"></a>      <span class="kw">case</span> eval env a <span class="kw">of</span></span>
<span id="cb16-41"><a href="#cb16-41" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Val</span> <span class="dt">True</span> <span class="ot">-&gt;</span> <span class="dt">Val</span> <span class="dt">False</span></span>
<span id="cb16-42"><a href="#cb16-42" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Val</span> <span class="dt">False</span> <span class="ot">-&gt;</span> <span class="dt">Val</span> <span class="dt">True</span></span>
<span id="cb16-43"><a href="#cb16-43" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Not</span> a&#39; <span class="ot">-&gt;</span> a&#39;</span>
<span id="cb16-44"><a href="#cb16-44" aria-hidden="true" tabindex="-1"></a>        a&#39; <span class="ot">-&gt;</span> <span class="dt">Not</span> a&#39;</span>
<span id="cb16-45"><a href="#cb16-45" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Val</span> b <span class="ot">-&gt;</span> <span class="dt">Val</span> b</span>
<span id="cb16-46"><a href="#cb16-46" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Var</span> name <span class="ot">-&gt;</span> fromMaybe (<span class="dt">Var</span> name) (M.lookup name env)</span>
<span id="cb16-47"><a href="#cb16-47" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-48"><a href="#cb16-48" aria-hidden="true" tabindex="-1"></a><span class="co">-- Returns `Nothing` if the expression is not satisfiable</span></span>
<span id="cb16-49"><a href="#cb16-49" aria-hidden="true" tabindex="-1"></a><span class="co">-- If the epxression is satisfiable returns `Just mapping` with a valid</span></span>
<span id="cb16-50"><a href="#cb16-50" aria-hidden="true" tabindex="-1"></a><span class="co">-- variable mapping</span></span>
<span id="cb16-51"><a href="#cb16-51" aria-hidden="true" tabindex="-1"></a><span class="ot">sat ::</span> <span class="dt">Expr</span> <span class="ot">-&gt;</span> <span class="dt">ContT</span> r <span class="dt">IO</span> (<span class="dt">Maybe</span> (<span class="dt">M.Map</span> <span class="dt">String</span> <span class="dt">Expr</span>))</span>
<span id="cb16-52"><a href="#cb16-52" aria-hidden="true" tabindex="-1"></a>sat expr <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb16-53"><a href="#cb16-53" aria-hidden="true" tabindex="-1"></a>  <span class="co">-- A stack of continuations</span></span>
<span id="cb16-54"><a href="#cb16-54" aria-hidden="true" tabindex="-1"></a>  try_next_ref <span class="ot">&lt;-</span> lift <span class="op">$</span> newIORef [] </span>
<span id="cb16-55"><a href="#cb16-55" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-56"><a href="#cb16-56" aria-hidden="true" tabindex="-1"></a>  callCC&#39; <span class="op">$</span> \exit <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb16-57"><a href="#cb16-57" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- Run `go` after reducing the expression to normal form without any</span></span>
<span id="cb16-58"><a href="#cb16-58" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- variable values</span></span>
<span id="cb16-59"><a href="#cb16-59" aria-hidden="true" tabindex="-1"></a>    res <span class="ot">&lt;-</span> go (eval M.empty expr) try_next_ref exit</span>
<span id="cb16-60"><a href="#cb16-60" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> res <span class="kw">of</span></span>
<span id="cb16-61"><a href="#cb16-61" aria-hidden="true" tabindex="-1"></a>      <span class="co">-- If there was a failure, backtrack and try again</span></span>
<span id="cb16-62"><a href="#cb16-62" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Nothing</span> <span class="ot">-&gt;</span> backtrack try_next_ref exit</span>
<span id="cb16-63"><a href="#cb16-63" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Just</span> vars <span class="ot">-&gt;</span> <span class="kw">case</span> eval vars expr <span class="kw">of</span></span>
<span id="cb16-64"><a href="#cb16-64" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- If the expression evaluates to true with the results of `go`, finish</span></span>
<span id="cb16-65"><a href="#cb16-65" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Val</span> <span class="dt">True</span> <span class="ot">-&gt;</span> exit res</span>
<span id="cb16-66"><a href="#cb16-66" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- Otherwise, backtrack and try again</span></span>
<span id="cb16-67"><a href="#cb16-67" aria-hidden="true" tabindex="-1"></a>        _ <span class="ot">-&gt;</span> backtrack try_next_ref exit</span>
<span id="cb16-68"><a href="#cb16-68" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-69"><a href="#cb16-69" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb16-70"><a href="#cb16-70" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- To backtrack: try to pop a continuation from the stack. If there are</span></span>
<span id="cb16-71"><a href="#cb16-71" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- none left, exit with failure. If there is a continuation then enter it.</span></span>
<span id="cb16-72"><a href="#cb16-72" aria-hidden="true" tabindex="-1"></a>    backtrack try_next_ref exit <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb16-73"><a href="#cb16-73" aria-hidden="true" tabindex="-1"></a>      try_next <span class="ot">&lt;-</span> lift <span class="op">$</span> readIORef try_next_ref</span>
<span id="cb16-74"><a href="#cb16-74" aria-hidden="true" tabindex="-1"></a>      <span class="kw">case</span> try_next <span class="kw">of</span></span>
<span id="cb16-75"><a href="#cb16-75" aria-hidden="true" tabindex="-1"></a>        [] <span class="ot">-&gt;</span> exit <span class="dt">Nothing</span></span>
<span id="cb16-76"><a href="#cb16-76" aria-hidden="true" tabindex="-1"></a>        next<span class="op">:</span>rest <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb16-77"><a href="#cb16-77" aria-hidden="true" tabindex="-1"></a>          lift <span class="op">$</span> writeIORef try_next_ref rest</span>
<span id="cb16-78"><a href="#cb16-78" aria-hidden="true" tabindex="-1"></a>          next</span>
<span id="cb16-79"><a href="#cb16-79" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb16-80"><a href="#cb16-80" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- It&#39;s a tree traversal, but with some twists</span></span>
<span id="cb16-81"><a href="#cb16-81" aria-hidden="true" tabindex="-1"></a>    go expr try_next_ref exit <span class="ot">=</span></span>
<span id="cb16-82"><a href="#cb16-82" aria-hidden="true" tabindex="-1"></a>      <span class="kw">case</span> expr <span class="kw">of</span></span>
<span id="cb16-83"><a href="#cb16-83" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- Twist 1: When we encounter a variable, we first continue as if it&#39;s</span></span>
<span id="cb16-84"><a href="#cb16-84" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- true, but also push a continuation on the stack where it is set to false</span></span>
<span id="cb16-85"><a href="#cb16-85" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Var</span> name <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb16-86"><a href="#cb16-86" aria-hidden="true" tabindex="-1"></a>          res <span class="ot">&lt;-</span> callCC&#39; <span class="op">$</span> \k <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb16-87"><a href="#cb16-87" aria-hidden="true" tabindex="-1"></a>            lift <span class="op">$</span> modifyIORef try_next_ref (k (<span class="dt">Val</span> <span class="dt">False</span>) <span class="op">:</span>)</span>
<span id="cb16-88"><a href="#cb16-88" aria-hidden="true" tabindex="-1"></a>            <span class="fu">pure</span> <span class="op">$</span> <span class="dt">Val</span> <span class="dt">True</span></span>
<span id="cb16-89"><a href="#cb16-89" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- When this program is first run, `res` = True. But if we pop and</span></span>
<span id="cb16-90"><a href="#cb16-90" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- enter the result of `k (Val False)`, we would end up back here</span></span>
<span id="cb16-91"><a href="#cb16-91" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- again, with `res` = False</span></span>
<span id="cb16-92"><a href="#cb16-92" aria-hidden="true" tabindex="-1"></a>          <span class="fu">pure</span> <span class="op">$</span> <span class="dt">Just</span> (M.singleton name res)</span>
<span id="cb16-93"><a href="#cb16-93" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Val</span> b <span class="ot">-&gt;</span> <span class="fu">pure</span> <span class="op">$</span> <span class="kw">if</span> b <span class="kw">then</span> <span class="dt">Just</span> M.empty <span class="kw">else</span> <span class="dt">Nothing</span></span>
<span id="cb16-94"><a href="#cb16-94" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- Twist 2: When we get to an Or, only one of the sides needs to be</span></span>
<span id="cb16-95"><a href="#cb16-95" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- satisfied. So we first continue by checking the left side, but also</span></span>
<span id="cb16-96"><a href="#cb16-96" aria-hidden="true" tabindex="-1"></a>        <span class="co">-- push a continuation where we check the right side instead.</span></span>
<span id="cb16-97"><a href="#cb16-97" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Or</span> a b <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb16-98"><a href="#cb16-98" aria-hidden="true" tabindex="-1"></a>          side <span class="ot">&lt;-</span> callCC&#39; <span class="op">$</span> \k <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb16-99"><a href="#cb16-99" aria-hidden="true" tabindex="-1"></a>            lift <span class="op">$</span> modifyIORef try_next_ref (k b <span class="op">:</span>)</span>
<span id="cb16-100"><a href="#cb16-100" aria-hidden="true" tabindex="-1"></a>            <span class="fu">pure</span> a</span>
<span id="cb16-101"><a href="#cb16-101" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- Similar to the `Var` example. First ruvn, `side` = a. But if later</span></span>
<span id="cb16-102"><a href="#cb16-102" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- we enter the saved continuation then we will return to this point</span></span>
<span id="cb16-103"><a href="#cb16-103" aria-hidden="true" tabindex="-1"></a>          <span class="co">-- in the program with `side` = b</span></span>
<span id="cb16-104"><a href="#cb16-104" aria-hidden="true" tabindex="-1"></a>          go side try_next_ref exit </span>
<span id="cb16-105"><a href="#cb16-105" aria-hidden="true" tabindex="-1"></a>        <span class="dt">And</span> a b <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb16-106"><a href="#cb16-106" aria-hidden="true" tabindex="-1"></a>          a_res <span class="ot">&lt;-</span> go a try_next_ref exit</span>
<span id="cb16-107"><a href="#cb16-107" aria-hidden="true" tabindex="-1"></a>          b_res <span class="ot">&lt;-</span> go b try_next_ref exit</span>
<span id="cb16-108"><a href="#cb16-108" aria-hidden="true" tabindex="-1"></a>          <span class="fu">pure</span> <span class="op">$</span> liftA2 M.union a_res b_res</span>
<span id="cb16-109"><a href="#cb16-109" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-110"><a href="#cb16-110" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Not</span> a <span class="ot">-&gt;</span> go a try_next_ref exit</span>
<span id="cb16-111"><a href="#cb16-111" aria-hidden="true" tabindex="-1"></a>        </span>
<span id="cb16-112"><a href="#cb16-112" aria-hidden="true" tabindex="-1"></a>        _ <span class="ot">-&gt;</span> go (eval M.empty expr) try_next_ref exit</span></code></pre></div>
<p>The solver sets all the variables to <code>True</code>, and if the full expression evaluates to <code>False</code> it flips one to <code>False</code> and automatically re-evaluates the expression, repeating the process untill either it finally evaluates to <code>True</code> or all possible combinations of boolean values have been tested. It’s not efficient, but it’s a wonderful illustration of the elegance that CPS enables.</p>
    ]]></content>
    
</entry>
<entry>
    <title>How to delete old NixOS boot configurations</title>
    <link href="https://blog.ielliott.io/how-to-delete-old-nixos-boot-configurations" />
    
    <id>https://blog.ielliott.io/how-to-delete-old-nixos-boot-configurations</id>
    
    <published>2017-03-24T00:00:00Z</published>
    <updated>2017-03-24T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/how-to-delete-old-nixos-boot-configurations"><![CDATA[<p><a href="https://nixos.org/">NixOS</a> is a Linux distribution with declarative
configuration management. Your system configuration is specified in a
set of files, and can run a command to update your system to the current
specification. A consequence of this is that your entire system
configuration can be versioned.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/how-to-delete-old-nixos-boot-configurations"><![CDATA[
      
      <p><a href="https://nixos.org/">NixOS</a> is a Linux distribution with declarative
configuration management. Your system configuration is specified in a
set of files, and can run a command to update your system to the current
specification. A consequence of this is that your entire system
configuration can be versioned.</p>
<p>Every time you rebuild your NixOS configuration, a new entry is added to
the bootloader. This is helpful if you ever make a configuration change
that breaks on your machine because you can reboot into the last known
working state and try something different.</p>
<p>If you don’t need to have access to all your old configurations, you
can delete them:</p>
<ol type="1">
<li><p><code>sudo nix-collect-garbage -d</code></p></li>
<li><p><code>sudo nixos-rebuild switch</code></p></li>
</ol>
<hr />
<p><em>30 December 2018</em></p>
<p>I don’t know if I was confused when I first wrote this, or if the process has
improved since then. Either way, these instructions are more complex
than necessary, so I’ve updated them.</p>
<ol type="1">
<li><p><del>Delete the old (excludes the current) package configurations for the
NixOS system <code>sudo nix-env -p /nix/var/nix/profiles/system --delete-generations old</code></del></p></li>
<li><p><del>Collect garbage <code>nix-collect-garbage -d</code></del></p></li>
<li><p><del>View the remaining generation <code>nix-env -p /nix/var/nix/profiles/system --list-generations</code>. Take note of this for the next step.</del></p></li>
<li><p><del>Remove unnecessary boot loader entries. I use <code>systemd-boot</code>, so all
my entries are located in <code>/boot/loader/entries</code>. To remove all the
old entries, run <code>sudo bash -c "cd /boot/loader/entries; ls | grep -v &lt;current-generation-name&gt; | xargs rm"</code> (you might want to back up
the entries somewhere to be safe)</del></p></li>
</ol>
    ]]></content>
    
</entry>
<entry>
    <title>Introduction to Unification</title>
    <link href="https://blog.ielliott.io/introduction-to-unification" />
    
    <id>https://blog.ielliott.io/introduction-to-unification</id>
    
    <published>2017-01-07T00:00:00Z</published>
    <updated>2017-01-07T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/introduction-to-unification"><![CDATA[<p>Unification is a vital process in the implementation of Hindley-Damas-Milner
type inference. In the <a href="http://web.cs.wpi.edu/~cs4536/c12/milner-damas_principal_types.pdf">original paper</a>
it is mentioned in passing as assumed knowledge, so here is an explanation of
unification in with a little help from the HM type theory.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/introduction-to-unification"><![CDATA[
      
      <p>Unification is a vital process in the implementation of Hindley-Damas-Milner
type inference. In the <a href="http://web.cs.wpi.edu/~cs4536/c12/milner-damas_principal_types.pdf">original paper</a>
it is mentioned in passing as assumed knowledge, so here is an explanation of
unification in with a little help from the HM type theory.</p>
<h2 id="what-is-unification"><a href="#what-is-unification">What is Unification?</a></h2>
<p>Unification is a method of solving equations by substitution. This sentence alone
doesn’t give enough information to implement an algorithm, so let’s define some
vocabulary to write a more rigorous definition.</p>
<p><code>term</code>: A term is an abstract syntax tree representing the language that will be used.
In order for unification to proceed, term must have some value that represents a
<code>variable</code>, and some values that represent <code>constants</code>- the idea being that <code>variables</code>
can be replaced during unification, but constants cannot.</p>
<p><code>equation</code>: An equation is a pair of terms, written <code>term_1 = term_2</code>.</p>
<p><code>syntactic equality</code>: Two terms are syntactically equal if their ASTs match
exactly.</p>
<p><code>equivalence</code>: Two terms are equivalent if there exists some substitution that would
make them syntactically equal.</p>
<p><code>solved</code>: An equation is solved if the left and right hand sides are syntactically
equal.</p>
<p><code>substitution</code>: A substitution is a set of mappings from variables to terms, written
<code>{ var_1 =&gt; term_1, ..., var_i =&gt; term_i }</code>.</p>
<p><code>application</code>: A substitution can be <code>applied</code> to a value containing variables - written <code>subs(value)</code>:</p>
<ul>
<li>term: by replacing variables with terms per each mapping</li>
<li>equation: by applying the substitution to both sides</li>
<li>set of equations: by applying the substitution to each element in the set</li>
<li>substitution: by applying the substitution to the right hand side of each mapping</li>
</ul>
<p>Applying an empty substitution to a value does not change the value.
For reasons that will be explained later, a substitution is only valid if every
variable on the left side of mapping does <em>not</em> occur in the term on the right
side of the respective mapping.</p>
<p><code>minimal</code>: A substitution is minimal if no variables in the right hand sides of
any mapping occur on any left hand side of any mapping. In other words, if
applying the substitution is idempotent: <code>subs(subs(value)) = subs(value)</code></p>
<p>With this vocabulary, we can now better define unification:</p>
<p><em>Given a set of equations <code>eqs</code>, find a minimal substitution <code>sub</code> such that
every equation in <code>sub(eqs)</code> is solved</em></p>
<h2 id="hindley-milner"><a href="#hindley-milner">Hindley-Milner</a></h2>
<p>Unification is the backbone of type inference in the HM type theory. The actual
type inference algorithm is not important here- just how unification works on
HM terms.</p>
<p>A term in HM is defined as <code>term := term -&gt; term | primitive | variable</code> where
<code>primitive</code> is an element of a set of primitive types and <code>variable</code> is a string.
respectively. To satisfy the requirements of unification, primitives are constants
and variables are, of course, variables.</p>
<p>Examples of syntactically equal HM terms:</p>
<ul>
<li><code>a</code> and <code>a</code></li>
<li><code>primitive</code> and <code>primitive</code></li>
<li><code>a -&gt; a</code> and <code>a -&gt; a</code></li>
</ul>
<p>Examples of equivalent HM terms:</p>
<ul>
<li><code>a</code> and <code>c</code></li>
<li><code>primitive</code> and <code>d</code></li>
<li><code>(a -&gt; b) -&gt; c</code> and <code>d -&gt; e</code></li>
</ul>
<p>When conducting type inference for an expression, its type is initially set to a
new variable. A set of equations is generated by traversing the expression’s AST,
then these equations are then unified, which yields a solution for the
expression’s type variable.</p>
<h2 id="an-algorithm"><a href="#an-algorithm">An Algorithm</a></h2>
<p>A simple unification algorithm can be described as follows:</p>
<pre><code>unify(equations):
  solutions := {}
  ix := 0
  while ix &lt; equations.length:
    equation := equations[ix]
    if solved(equation):
      ix++
      continue

    substitution := {}  
    if is_variable(equation.lhs):
      if occurs(equation.lhs, equation.rhs):
        error(&quot;Variable occurred on both sides of an equation&quot;)
      substitution := {current.lhs =&gt; current.rhs}
      ix++
    elif is_variable(equation.rhs):
      swap_sides(equations[ix])
    elif equivalent(equation.lhs, equation.rhs):
      substitution := unify(implied_equations(equation))
    else:
      error(&quot;Cannot unify non-equivalent terms&quot;)

    substitution.apply(solutions)
    substitution.apply(equations)
    solutions.union(substitution)

  return solutions</code></pre>
<p>In essence the algorithm is “rearrange an equation so it is a solution, update
everything according to this knowledge, remember the solution and continue”.
<a href="https://en.wikipedia.org/wiki/System_of_linear_equations#Elimination_of_variables">Sounds like something we did a lot in school…</a></p>
<h3 id="why-check-occurs"><a href="#why-check-occurs">Why check <code>occurs</code>?</a></h3>
<p>This algorithm requires a substitution to ‘eliminate’ a variable from the problem.
If a variable could also be on the right side of a substitution then it would
not be eliminated, constructing an infinite solution.</p>
<p>To demonstrate, let’s unify the HM equations <code>{a = b -&gt; c, a = d, b = d, a = c}</code> without
the occurs check:</p>
<pre><code>equations = {a = b -&gt; c, a = d, b = d, a = c}
solutions = {}

equations = {b -&gt; c = d, b = d, b -&gt; c = c} (removed a = b -&gt; c, applied a =&gt; b -&gt; c)
solutions = {a =&gt; b -&gt; c} (added a =&gt; b -&gt; c)

equations = {b = b -&gt; c, b -&gt; c = c} (removed b -&gt; c = d, applied d = b -&gt; c)
solutions = {a =&gt; b -&gt; c, d =&gt; b -&gt; c} (added d =&gt; b -&gt; c)

equations = {(b -&gt; c) -&gt; c = c} (removed b = b -&gt; c, applied b = b -&gt; c)
solutions = {a =&gt; (b -&gt; c) -&gt; c, d =&gt; (b -&gt; c) -&gt; c, b =&gt; b -&gt; c} (applied then added b =&gt; b -&gt; c)

equations = {}
solutions = {a =&gt; (b -&gt; (b -&gt; c) -&gt; c) -&gt; c, d =&gt; (b -&gt; (b -&gt; c) -&gt; c) -&gt; (b -&gt; c) -&gt; c, b =&gt; b -&gt; (b -&gt; c) -&gt; c, c = (b -&gt; c) -&gt; c} (applied then added c =&gt; (b -&gt; c) -&gt; c)

apply solutions to original equations - remember that the solutions should solve all the original equations:

a = b -&gt; c
b -&gt; (b -&gt; c) -&gt; c = b -&gt; c (using a =&gt; ...)
b -&gt; (b -&gt; (b -&gt; c) -&gt; c) -&gt; (b -&gt; c) -&gt; c = b -&gt; (b -&gt; c) -&gt; c (using c =&gt; ...)

no matter how many times we do this the equation will never be solved...</code></pre>
<p>Omitting the occurs check does <em>not</em> unify the equations according our definition.</p>
<h2 id="resources"><a href="#resources">Resources</a></h2>
<p>The <a href="https://en.wikipedia.org/wiki/Unification_(computer_science)">Wikipedia entry for Unification</a>
is amazing and goes into much more depth.</p>
    ]]></content>
    
</entry>
<entry>
    <title>Why LINQ (well, C#) is Broken</title>
    <link href="https://blog.ielliott.io/why-LINQ-is-broken" />
    
    <id>https://blog.ielliott.io/why-LINQ-is-broken</id>
    
    <published>2016-10-24T00:00:00Z</published>
    <updated>2016-10-24T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/why-LINQ-is-broken"><![CDATA[<p>LINQ is a system that provides a flexible query interface for .NET languages.
It allows a user to write queries over arbitrary data using an in-built
SQL-like syntax. This syntactic sugar is mapped to method calls at compile time,
so any data structure that implements the correct methods can be used with LINQ.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/why-LINQ-is-broken"><![CDATA[
      
      <p>LINQ is a system that provides a flexible query interface for .NET languages.
It allows a user to write queries over arbitrary data using an in-built
SQL-like syntax. This syntactic sugar is mapped to method calls at compile time,
so any data structure that implements the correct methods can be used with LINQ.</p>
<p>The essential methods for enabling LINQ support are <code>Select</code> and <code>SelectMany</code>,
implemented as extension methods. They have the following types:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode c#"><code class="sourceCode cs"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>SomeData<span class="op">&lt;</span>B<span class="op">&gt;</span> Select<span class="op">&lt;</span>A<span class="op">,</span>B<span class="op">&gt;(</span><span class="kw">this</span> SomeData<span class="op">&lt;</span>A<span class="op">&gt;</span> a<span class="op">,</span> Func<span class="op">&lt;</span>A<span class="op">,</span>B<span class="op">&gt;</span> f<span class="op">)</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>SomeData<span class="op">&lt;</span>B<span class="op">&gt;</span> SelectMany<span class="op">&lt;</span>A<span class="op">,</span>B<span class="op">&gt;(</span><span class="kw">this</span> SomeData<span class="op">&lt;</span>A<span class="op">&gt;</span> a<span class="op">,</span> Func<span class="op">&lt;</span>A<span class="op">,</span>SomeData<span class="op">&lt;</span>B<span class="op">&gt;&gt;</span> f<span class="op">)</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>SomeData<span class="op">&lt;</span>C<span class="op">&gt;</span> SelectMany<span class="op">&lt;</span>A<span class="op">,</span>B<span class="op">,</span>C<span class="op">&gt;(</span><span class="kw">this</span> SomeData<span class="op">&lt;</span>A<span class="op">&gt;</span> a<span class="op">,</span> Func<span class="op">&lt;</span>A<span class="op">,</span>SomeData<span class="op">&lt;</span>B<span class="op">&gt;&gt;</span> f<span class="op">,</span> Func<span class="op">&lt;</span>A<span class="op">,</span>B<span class="op">,</span>C<span class="op">&gt;</span> g<span class="op">)</span> <span class="co">// Overloaded to reduce levels of nesting</span></span></code></pre></div>
<p>With implementations of these three methods, it is possible to write a query
expression such as:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode c#"><code class="sourceCode cs"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>SomeData<span class="op">&lt;</span>A<span class="op">&gt;</span> myA <span class="op">=</span> <span class="op">...;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>SomeData<span class="op">&lt;</span>B<span class="op">&gt;</span> myB <span class="op">=</span> <span class="op">...;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>Func<span class="op">&lt;</span>A<span class="op">,</span>B<span class="op">,</span>C<span class="op">&gt;</span> f <span class="op">=</span> <span class="op">...;</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>SomeData<span class="op">&lt;</span>C<span class="op">&gt;</span> myC <span class="op">=</span> from a <span class="kw">in</span> myA</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>                  from b <span class="kw">in</span> myB</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>                  select <span class="fu">f</span><span class="op">(</span>a<span class="op">,</span>b<span class="op">);</span></span></code></pre></div>
<p>which will be compiled to something like:
<code>SomeData&lt;C&gt; output = justWord.SelectMany(a =&gt; myB, (a, b) =&gt; f(a, b));</code></p>
<p>Readers who are familiar with Haskell or similar functional languages will
notice that <code>Select</code> is <code>fmap</code>, <code>SelectMany</code> is <code>&gt;&gt;=</code> and the
<code>from .. in .. select</code> syntax is equivalent to Monad comprehensions. The above
code would be written in Haskell as follows:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>myA <span class="ot">=</span> <span class="op">...</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>myB <span class="ot">=</span> <span class="op">...</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>f a b <span class="ot">=</span> <span class="op">...</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>myC <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>  a <span class="ot">&lt;-</span> myA</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>  b <span class="ot">&lt;-</span> myB</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>  <span class="fu">return</span> <span class="op">$</span> f a b</span></code></pre></div>
<p>LINQ was designed to bring Monad comprehensions to C#. And it does. Almost.</p>
<p>Consider our query from earlier:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode c#"><code class="sourceCode cs"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="op">...</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>SomeData<span class="op">&lt;</span>C<span class="op">&gt;</span> myC <span class="op">=</span> from a <span class="kw">in</span> myA</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>                  from b <span class="kw">in</span> myB</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>                  select <span class="fu">f</span><span class="op">(</span>a<span class="op">,</span>b<span class="op">);</span></span></code></pre></div>
<p>This seems like a common pattern. We don’t want to write this code over and
over, so we abstract <code>myA</code>, <code>myB</code> and <code>f</code> and make the query into a method.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode c#"><code class="sourceCode cs"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>SomeData<span class="op">&lt;</span>C<span class="op">&gt;</span> CombineWith<span class="op">&lt;</span>A<span class="op">,</span>B<span class="op">,</span>C<span class="op">&gt;(</span>SomeData<span class="op">&lt;</span>A<span class="op">&gt;</span> myA<span class="op">,</span> SomeData<span class="op">&lt;</span>B<span class="op">&gt;</span> myB<span class="op">,</span> Func<span class="op">&lt;</span>A<span class="op">,</span>B<span class="op">,</span>C<span class="op">&gt;</span> f<span class="op">)</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">return</span> from a <span class="kw">in</span> myA from b <span class="kw">in</span> myB select <span class="fu">f</span><span class="op">(</span>a<span class="op">,</span>b<span class="op">);</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Now say we define a new data type to use with LINQ, call it <code>OtherData&lt;A&gt;</code>, and
implement <code>Select</code> and <code>SelectMany</code> appropriately. We also want to implement
<code>CombineWith</code> because <code>from .. in .. from .. in .. select ..</code> is still a common
pattern that we want to avoid writing:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode c#"><code class="sourceCode cs"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>OtherData<span class="op">&lt;</span>C<span class="op">&gt;</span> CombineWith<span class="op">&lt;</span>A<span class="op">,</span>B<span class="op">,</span>C<span class="op">&gt;(</span>OtherData<span class="op">&lt;</span>A<span class="op">&gt;</span> myA<span class="op">,</span> OtherData<span class="op">&lt;</span>B<span class="op">&gt;</span> myB<span class="op">,</span> Func<span class="op">&lt;</span>A<span class="op">,</span>B<span class="op">,</span>C<span class="op">&gt;</span> f<span class="op">)</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">return</span> from a <span class="kw">in</span> myA from b <span class="kw">in</span> myB select <span class="fu">f</span><span class="op">(</span>a<span class="op">,</span>b<span class="op">);</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>There is a pattern emerging. For every data type that we want to use with LINQ,
one must reimplement all LINQ-specific methods specifically for that type.</p>
<p>This is an issue because it grossly violates DRY (don’t repeat yourself).
A well-written program should not have duplicated code - it makes maintenance
more laborious and increases the chance of bugs.</p>
<p>So in an effort to save ourselves time, we should abstract over this common
pattern. We require a function that specifies</p>
<blockquote>
<p>for all generic classes <code>F&lt;???&gt;</code> implementing <code>Select</code> and <code>SelectMany</code>, given
an instance of <code>F</code> containing <code>A</code>s, another instance of <code>F</code> containing <code>B</code>s,
and a <code>Func&lt;A,B,C</code>, return an <code>F</code> containing <code>C</code>s</p>
</blockquote>
<p>It turns out that it’s actually impossible to write this method in C#. I’d like
to write something like
<code>F&lt;C&gt; CombineWith&lt;F&lt;?&gt;,A,B,C&gt;(F&lt;A&gt; myA, F&lt;B&gt; myB, Func&lt;A,B,C&gt; f)</code>, but C# only
allows abstraction over non-generic types.</p>
<p>To add a little more weight to this revelation, let’s imagine if we could
not abstract over the contents of a list ie. the method
<code>List&lt;A&gt; Sort&lt;A&gt;(List &lt;A&gt; input)</code> cannot be expressed in this language. Due to
this limitation, we would have to create a new list class every time we needed
a different element type inside the list, then reimplement <code>Sort</code> for each new
class.</p>
<blockquote>
<p><code>ListOfInt.Sort</code>
<code>ListOfBool.Sort</code>
<code>ListOfSomeData.Sort</code>
…</p>
</blockquote>
<p>This is again a terrible violation of the “don’t repeat yourself” principle.
You write <code>n</code> implementations of <code>Sort</code>, where <code>n</code> is the number of sortable
classes. Imagine that each implementation used the
<a href="http://envisage-project.eu/proving-android-java-and-python-sorting-algorithm-is-broken-and-how-to-fix-it/">proven incorrect version of TimSort</a>.
If you wanted to implement the correct version, you would have to update <code>n</code>
methods.</p>
<p>Also consider the implementation of
<code>List&lt;B&gt; Map&lt;A,B&gt;(List&lt;A&gt; input, Func&lt;A,B&gt; f)</code> in a generic-less language. You
would have to write a different method for each inhabitant of <code>A</code> and <code>B</code></p>
<blockquote>
<p><code>ListOfInt.MapToListOfInt</code>
<code>ListOfInt.MapToListOfBool</code>
<code>ListOfInt.MapToListOfSomeData</code>
<code>ListOfBool.MapToListOfBool</code>
…</p>
</blockquote>
<p>You write <code>n^2</code> <code>Map</code> methods where <code>n</code> is the number of of mappable classes.</p>
<p>More generally, in this generic-less language, you write <code>O(n^m)</code> where <code>m</code> is
the sum of should-be-generic inputs and should-be-generic outputs, and <code>n</code> is
the number of should-be-generic classes.</p>
<p>This exponential growth of redundant nonsense also applies to our <code>CombineWith</code>
issue. For every LINQ-able class, you have to write a separate implementation
of <code>CombineWith</code>, even though it’s exactly the same code!</p>
<p>Haskell (and other sane functional languages) uses a concept called “Higher
Kinded Types” to address this problem. Every type has a “kind” (denoted <code>*</code>). In
C#, every type must have kind <code>*</code>. Higher-kinded types are functions from kinds
to kinds. Given data declaration that has a single type variable, say
<code>Maybe a = Just a | Nothing</code>, we say that <code>Maybe</code> has kind <code>* -&gt; *</code>, which means
that it is a higher-kinded type that takes a type of kind <code>*</code> and returns a type
of kind <code>*</code>. In C#, every type must have kind <code>*</code> ie. if you have a defined the
class <code>List&lt;A&gt;</code> then you get a compile error if you refer to <code>List</code> without
the type argument.</p>
<p>Let’s take another look the Haskell implementation of <code>CombineWith</code>:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ot">combineWith ::</span> <span class="dt">Monad</span> m <span class="ot">=&gt;</span> m a <span class="ot">-&gt;</span> m b <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> b <span class="ot">-&gt;</span> c) <span class="ot">-&gt;</span> m c</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>combineWith myA myB f <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>  a <span class="ot">&lt;-</span> myA</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>  b <span class="ot">&lt;-</span> myB</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>  <span class="fu">return</span> <span class="op">$</span> f a b</span></code></pre></div>
<p>In this function, and the definition of the Monad typeclass (read: interface)<code>m</code>
implicitly has kind <code>* -&gt; *</code>. This function will work for any type that is
an instance of Monad (read: implements the Monad interface). In Haskell, this
code only needs to be written once. The cost of implementation and maintenance
of a group of functions has gone from O(n^m) to O(1).</p>
<p>Now you might say, “Well, I don’t use LINQ like that. I only use it for
<code>IEnumerable</code> things”. This is akin to a user of our imaginary generic-less
language saying “Well, I don’t use Sort like that. I only sort lists of
integers”. It is agreed that a language without generics is counter to
productivity. It follows that a language without higher-kinded types is also
counter to productivity.</p>
    ]]></content>
    
</entry>
<entry>
    <title>Search and Replace in Multiple Files</title>
    <link href="https://blog.ielliott.io/search-and-replace-in-multiple-files" />
    
    <id>https://blog.ielliott.io/search-and-replace-in-multiple-files</id>
    
    <published>2015-07-25T00:00:00Z</published>
    <updated>2015-07-25T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/search-and-replace-in-multiple-files"><![CDATA[<p>Last semester I had to write a static website by hand with no templating
resulting in a lot of duplicated code across multiple pages. I had already
finished most of the project when I realised that the main page of the
project should be named <code>index.html</code> instead of <code>home.html</code>. I renamed the
file, but that left me with countless references to “home.html” that needed
to be changed, and I wanted to change them all at once. Enter <code>sed</code>.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/search-and-replace-in-multiple-files"><![CDATA[
      
      <pre><code>$ sed -i &quot;s/pattern/replacement/g&quot; FILES</code></pre>
<h2 id="the-story"><a href="#the-story">The Story</a></h2>
<p>Last semester I had to write a static website by hand with no templating
resulting in a lot of duplicated code across multiple pages. I had already
finished most of the project when I realised that the main page of the
project should be named <code>index.html</code> instead of <code>home.html</code>. I renamed the
file, but that left me with countless references to “home.html” that needed
to be changed, and I wanted to change them all at once. Enter <code>sed</code>.</p>
<p><code>sed</code> allows the user to write programs which operate on streams of text.
It is run using the syntax</p>
<pre><code>$ sed OPTIONS.. [SCRIPT] [FILENAME..]</code></pre>
<p>To search and replace using <code>sed</code> we use the <code>s</code> command of the form
<code>s/regex/replacement/flags</code>. Our <code>sed</code> script would become
<code>s/home\.html/index.html/g</code>. The <code>.</code> needs to be escaped because <code>.</code> on its own
matches any character in regex. The <code>g</code> flag means to replace every occurrence
of the pattern, instead of just the first.</p>
<p>By default, <code>sed</code> will only write the altered text to <code>stdout</code>, so we need to
use the <code>-i</code> flag to make the alterations inside the source file.</p>
<p>The final command is now</p>
<pre><code>$ sed -i &quot;s/home\.html/index.html/g&quot; *.html</code></pre>
<p>which will apply the sed program to all the HTML files in the directory. Easy!</p>
    ]]></content>
    
</entry>
<entry>
    <title>The Programming Thought Process: Fizzbuzz</title>
    <link href="https://blog.ielliott.io/the-programming-thought-process-fizzbuzz" />
    
    <id>https://blog.ielliott.io/the-programming-thought-process-fizzbuzz</id>
    
    <published>2015-03-04T00:00:00Z</published>
    <updated>2015-03-04T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/the-programming-thought-process-fizzbuzz"><![CDATA[<p>With so many programming languages and frameworks at our disposal, it is
too easy to believe that knowledge of many tools is the defining characteristic
of a good programmer. However, many experienced programmers will assert that
it isn’t the languages you know, but your ability to solve problems that
defines you as a programmer.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/the-programming-thought-process-fizzbuzz"><![CDATA[
      
      <p>With so many programming languages and frameworks at our disposal, it is
too easy to believe that knowledge of many tools is the defining characteristic
of a good programmer. However, many experienced programmers will assert that
it isn’t the languages you know, but your ability to solve problems that
defines you as a programmer.</p>
<p>In this article I will attempt to explain some of the instinctual problem
solving techniques that experienced programmers use. Our problem will be
“fizzbuzz”; a notorious yet straightforward problem used to separate programmers
from non-programmers in job interviews. Its specification:</p>
<blockquote>
<p>Write a program that prints the numbers from 1 to 100. But for multiples of
three print “Fizz” instead of the number and for the multiples of five print
“Buzz”. For numbers which are multiples of both three and five print “FizzBuzz”.</p>
</blockquote>
<p>The first step in creating an answer is to examine the specification text
for keywords that you can translate into code. Consider the words “from
1 to 100”. If we want to access every number from 1 to 100, then the best
approach is to use a loop. All the other instructions apply to each individual
number, so the loop will contain this logic. <code>for</code> and <code>while</code> loops are
equally valid ways to complete the task, however I’ll use a for loop for this
example as it looks much cleaner.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">1</span>,<span class="dv">101</span>): <span class="co"># range(a,b) has range a &lt;= i &lt; b</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    <span class="co"># do some things</span></span></code></pre></div>
<p>The next few lines of the spec outline three conditions which could change what
will be printed. These can all be expressed using “if-else” statements due to
their boolean nature. Additionally, if the none of the conditions are
satisfied, then the number is to be printed. This “default” behaviour can be
specified in the “else” section of the statement.</p>
<p>When there are multiple “if-else” statements checking the same variable, it’s
best to use “elif” statement for all the options instead of nested “if-else”.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">1</span>,<span class="dv">101</span>):</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> multiple_of_three(i):</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>        <span class="bu">print</span>(<span class="st">&quot;Fizz&quot;</span>)</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">elif</span> multiple_of_five(i):</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>        <span class="bu">print</span>(<span class="st">&quot;Buzz&quot;</span>)</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">elif</span> multiple_of_three_and_five(i):</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>        <span class="bu">print</span>(<span class="st">&quot;FizzBuzz&quot;</span>)</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">else</span>:</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>        <span class="bu">print</span>(i)</span></code></pre></div>
<p>Here I’ve used some placeholder functions to express the divisibility of the
number, but how how should they be implemented? The simplest answer is to use
the modulus operator (<code>%</code>). <code>a % b</code> calculates the remainder of <code>a / b</code>, so the
three multiple functions could be replaced by <code>i % 3 == 0</code>, <code>i % 5 == 0</code> and
<code>i % 3 == 0 and i % 5 == 0</code>:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">1</span>,<span class="dv">101</span>):</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> i <span class="op">%</span> <span class="dv">3</span> <span class="op">==</span> <span class="dv">0</span>:</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>        <span class="bu">print</span>(<span class="st">&quot;Fizz&quot;</span>)</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">elif</span> i <span class="op">%</span> <span class="dv">5</span> <span class="op">==</span> <span class="dv">0</span>:</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>        <span class="bu">print</span>(<span class="st">&quot;Buzz&quot;</span>)</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">elif</span> i <span class="op">%</span> <span class="dv">3</span> <span class="op">==</span> <span class="dv">0</span> <span class="kw">and</span> i <span class="op">%</span> <span class="dv">5</span> <span class="op">==</span> <span class="dv">0</span>:</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>        <span class="bu">print</span>(<span class="st">&quot;FizzBuzz&quot;</span>)</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">else</span>:</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>        <span class="bu">print</span>(i)</span></code></pre></div>
<p>If one didn’t know of the modulus operator, however, the same functionality
could be created using arithmetic:</p>
<p>A number <code>a</code> is a multiple of another number <code>b</code> if <code>a / b</code> has no remainder.
There exists integers <code>q</code> and <code>r</code> such that <code>a = q * b + r</code>. If <code>a</code> is a
multiple of <code>b</code> then <code>a / b  = q</code>, otherwise <code>a / b = q + r / b</code>. This means
that for all <code>r</code>, <code>q = floor(a / b)</code>. Thus if <code>a - b * floor(a / b) = 0</code> then
<code>a</code> is a multiple of <code>b</code>:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> math <span class="im">import</span> floor <span class="co"># import the floor function from Python&#39;s math module</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> multiple_of(a,b):</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>    <span class="co"># if a is a multiple of b</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> (a <span class="op">-</span> (b <span class="op">*</span> floor(a<span class="op">/</span>b)) <span class="op">==</span> <span class="dv">0</span>)</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">1</span>,<span class="dv">101</span>):</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> multiple_of(i,<span class="dv">3</span>):</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>        <span class="bu">print</span>(<span class="st">&quot;Fizz&quot;</span>)</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>    <span class="cf">elif</span> multiple_of(i,<span class="dv">5</span>):</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>        <span class="bu">print</span>(<span class="st">&quot;Buzz&quot;</span>)</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>    <span class="cf">elif</span> multiple_of(i,<span class="dv">3</span>) <span class="kw">and</span> multiple_of(i,<span class="dv">5</span>):</span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>        <span class="bu">print</span>(<span class="st">&quot;FizzBuzz&quot;</span>)</span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>    <span class="cf">else</span>:</span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>        <span class="bu">print</span>(i)</span></code></pre></div>
<p>The next step is testing the code. For simple programs this can be done by
running the code and looking at the output.</p>
<pre><code>$ python fizzbuzz.py
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
Fizz
...</code></pre>
<p>The output of the program lacks any mentions of “FizzBuzz”, printing “Fizz”
instead. This is a clue that the problem lies in the condition evalution.
The numbers divisible by both three and five are evaluated as just being
divisible by three. To fix this, either</p>
<ul>
<li>Move the “FizzBuzz” condition so it is evaluated first; or;</li>
<li>Add extra parameters to the “Fizz” and “Buzz” conditions to clarify that they
should not trigger when a number is divisible by both three and five.</li>
</ul>
<div class="sourceCode" id="cb6"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>...</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="co"># 1. changing condition evaluation order</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> i <span class="op">%</span> <span class="dv">3</span> <span class="op">==</span> <span class="dv">0</span> <span class="kw">and</span> i <span class="op">%</span> <span class="dv">5</span> <span class="op">==</span> <span class="dv">0</span>:</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>    <span class="bu">print</span>(<span class="st">&quot;FizzBuzz&quot;</span>)</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="cf">elif</span> i <span class="op">%</span> <span class="dv">3</span> <span class="op">==</span> <span class="dv">0</span>: <span class="co"># numbers divisible by both three and five will never reach this condition</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>    <span class="bu">print</span>(<span class="st">&quot;Fizz&quot;</span>)</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a><span class="cf">elif</span> i <span class="op">%</span> <span class="dv">5</span> <span class="op">==</span> <span class="dv">0</span>:</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>    <span class="bu">print</span>(<span class="st">&quot;Buzz&quot;</span>)</span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a><span class="cf">else</span>:</span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>    <span class="bu">print</span>(i)</span></code></pre></div>
<div class="sourceCode" id="cb7"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>...</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="co"># 2. clarifying logic</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> i <span class="op">%</span> <span class="dv">3</span> <span class="op">==</span> <span class="dv">0</span> <span class="kw">and</span> <span class="kw">not</span> i <span class="op">%</span> <span class="dv">5</span> <span class="op">==</span> <span class="dv">0</span>: <span class="co"># we want to print fizz for numbers that are divisible by three and NOT divisible by five</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>    <span class="bu">print</span>(<span class="st">&quot;Fizz&quot;</span>)</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="cf">elif</span> i <span class="op">%</span> <span class="dv">5</span> <span class="op">==</span> <span class="dv">0</span> <span class="kw">and</span> <span class="kw">not</span> i <span class="op">%</span> <span class="dv">3</span> <span class="op">==</span> <span class="dv">0</span>: <span class="co"># the opposite is true here</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>    <span class="bu">print</span>(<span class="st">&quot;Buzz&quot;</span>)</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="cf">elif</span> i <span class="op">%</span> <span class="dv">3</span> <span class="op">==</span> <span class="dv">0</span> <span class="kw">and</span> i <span class="op">%</span> <span class="dv">5</span> <span class="op">==</span> <span class="dv">0</span>:</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>    <span class="bu">print</span>(<span class="st">&quot;FizzBuzz&quot;</span>)</span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a><span class="cf">else</span>:</span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a>    <span class="bu">print</span>(i)</span></code></pre></div>
<p>Either way, the program now functions correctly.</p>
<p>Now, I can imagine that some people would have questions like “How would I
recognise that loops would be useful in this?” or “How do I know to use if-else
statements for this problem?” There are three answers to these kinds of
questions:</p>
<ol type="1">
<li><p>Know your tools.</p>
<p>Knowledge of languages and tools does not define you as as programmer, but
this knowledge does influence how effectively you can solve a problem using a
given language. Strong knowledge of language features will give you an
indication of which tasks are easy or difficult using that language, and
and help you use full potential of the language to complete the task.</p></li>
<li><p>Practise.</p>
<p>If you only read and never practise you will never reach your full potential.
Practise is essential in reinforcing learning.</p></li>
<li><p>Get feedback.</p>
<p>Learning is much easier when you have someone more experienced to guide you.
As well as practising on your own, get your work reviewed by someone who
knows more than you. They will easily be able to point inefficient or
redundant code. Additionally, you need to take note of the tips they give you
and then practise integrating them when you work. If you don’t take advice to
heart then you will never improve.</p></li>
</ol>
<p>In summary, when attempting programming problems you need to:</p>
<ul>
<li>Identify keywords</li>
<li>Translate them to code</li>
<li>Test the code</li>
<li>Look for clues regarding any errors</li>
<li>Change the code based on any clues you found</li>
<li>Rinse and repeat</li>
</ul>
<p>Learn your tools, use the tools and get feedback on your work to ensure contant
improvement.</p>
<p>Good luck.</p>
    ]]></content>
    
</entry>
<entry>
    <title>A Practical Introduction to Monad Transformers</title>
    <link href="https://blog.ielliott.io/a-practical-introduction-to-monad-transformers" />
    
    <id>https://blog.ielliott.io/a-practical-introduction-to-monad-transformers</id>
    
    <published>2015-02-01T00:00:00Z</published>
    <updated>2015-02-01T00:00:00Z</updated>
    
    <summary type="html" xml:base="https://blog.ielliott.io/a-practical-introduction-to-monad-transformers"><![CDATA[<p>Monad transformers combine the functionality of two monads into one. They are often used
as a way to “flatten” nested monads, but are also used to enable interactions between
monads that, when used seperately, would be incredibly difficult to implement.</p>]]></summary>
    
    
    <content type="html" xml:base="https://blog.ielliott.io/a-practical-introduction-to-monad-transformers"><![CDATA[
      
      <p>Monad transformers combine the functionality of two monads into one. They are often used
as a way to “flatten” nested monads, but are also used to enable interactions between
monads that, when used seperately, would be incredibly difficult to implement.</p>
<h2 id="the-task"><a href="#the-task">The Task</a></h2>
<p>You input a number and want to manipulate it while printing the
result each time. If there were no intermediate IO operations we could use the state monad
with the following state changes:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ot">add ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">State</span> <span class="dt">Int</span> ()</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>add n <span class="ot">=</span> state <span class="op">$</span> \s <span class="ot">-&gt;</span> ((),s <span class="op">+</span> n)</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="fu">subtract</span><span class="ot"> ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">State</span> <span class="dt">Int</span> ()</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="fu">subtract</span> n <span class="ot">=</span> state <span class="op">$</span> \s <span class="ot">-&gt;</span> ((),s <span class="op">-</span> n)</span></code></pre></div>
<p>chain them together:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ot">manyOperations ::</span> <span class="dt">State</span> <span class="dt">Int</span> ()</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>manyOperations <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    add <span class="dv">1</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    <span class="fu">subtract</span> <span class="dv">3</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    add <span class="dv">5</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>    add <span class="dv">7</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    <span class="fu">subtract</span> <span class="dv">22</span></span></code></pre></div>
<p>then get the result:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>(_,result) <span class="ot">=</span> runState manyOperations <span class="dv">5</span><span class="ot"> ::</span> ((),<span class="dt">Int</span>)</span></code></pre></div>
<p>Now let’s consider how to print the state. If we want to preserve the above chaining syntax, we need
a monad where:</p>
<ol type="1">
<li>We can do stateful computations</li>
<li>Our IO functions have access variables inside the computation</li>
</ol>
<p>This monad is called the state monad transformer.</p>
<h2 id="the-solution"><a href="#the-solution">The Solution</a></h2>
<p>The state monad transformer is defined as:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">StateT</span> s m a <span class="ot">=</span> <span class="dt">StateT</span> {<span class="ot"> runStateT ::</span> s <span class="ot">-&gt;</span> m (a,s) }</span></code></pre></div>
<p><a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>Meaning that given an initial state <code>s</code> and a state transformer <code>st</code>, we can call <code>runStateT st s</code> to get
a monad containing the state tuple.</p>
<p>The real beauty (or magic, as some would say) of this monad comes from the bind function. Let’s take a look
at its definition:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ot">(&gt;&gt;=) ::</span> <span class="dt">Monad</span> n <span class="ot">=&gt;</span> <span class="dt">StateT</span> s n a <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">StateT</span> s n a) <span class="ot">-&gt;</span> <span class="dt">StateT</span> s n a</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>m <span class="op">&gt;&gt;=</span> k  <span class="ot">=</span> <span class="dt">StateT</span> <span class="op">$</span> \ s <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">~</span>(a, s&#39;) <span class="ot">&lt;-</span> runStateT m s</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>    runStateT (k a) s&#39;</span></code></pre></div>
<p>Time to break it down. <code>m</code> is a state transformer. <code>k</code> is a function that takes a result of type <code>a</code>, and returns
a state transformer. The final state transformer, when run with an initial state, does the following:</p>
<ol type="1">
<li>Gets the result and state of running the computation in <code>m</code> with the initial state <code>s</code></li>
<li>Passes the result of (1) to the function <code>k</code>, returning a different state transformer</li>
<li>Runs the computation created in (2) using the state returned in (1)</li>
<li>Wraps the result</li>
</ol>
<p>This means that we will be able to keep using a simple chained sequence of monads.</p>
<p>How does this relate to the problem at hand?</p>
<p>The monad component of the state transformer allows us to execute IO operations which have access to the state
<em>during</em> the computation. Here is how the <code>add</code> and <code>subtract</code> functions can be written using the state transformer
monad:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ot">add ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">StateT</span> <span class="dt">Int</span> <span class="dt">IO</span> ()</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>add n <span class="ot">=</span> <span class="dt">StateT</span> <span class="op">$</span> \s <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>    <span class="fu">print</span> (s<span class="op">+</span>n)</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>    <span class="fu">return</span> ((),s<span class="op">+</span>n)</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="fu">subtract</span><span class="ot"> ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">StateT</span> <span class="dt">Int</span> <span class="dt">IO</span> ()</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="fu">subtract</span> n <span class="ot">=</span> <span class="dt">StateT</span> <span class="op">$</span> \s <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>    <span class="fu">print</span> (s<span class="op">-</span>n)</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>    <span class="fu">return</span> ((),s<span class="op">-</span>n)</span></code></pre></div>
<p>We can still chain them using the same syntax as before:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ot">manyOperations ::</span> <span class="dt">StateT</span> <span class="dt">Int</span> <span class="dt">IO</span> ()</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>manyOperations <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>    add <span class="dv">1</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>    <span class="fu">subtract</span> <span class="dv">3</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>    add <span class="dv">5</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>    add <span class="dv">7</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>    <span class="fu">subtract</span> <span class="dv">22</span></span></code></pre></div>
<p>and run it:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> runStateT manyOperations <span class="dv">5</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- output:</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- 6</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- 3</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- 8</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- 15</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- -7</span></span></code></pre></div>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p><code>newtype</code> creates a strict, isomorphic type with a single value constructor. If all that was too much, just imagine that <code>newtype</code> rearranges an existing type into a more pleasant one.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
    ]]></content>
    
</entry>

</feed>