<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text" xml:lang="en">f : ⊥ x ⊥ → ⊥ | Clojure</title>
  <link type="application/atom+xml" href="https://www.arrdem.com/feeds/clojure.xml" rel="self"/>
  <link type="text/html" href="https://www.arrdem.com" rel="alternate"/>
  <updated>2026-05-12T00:00:59+00:00</updated>
  <id>http://www.ardem.com/</id>
  <author>
    <name>Reid McKenzie</name>
  </author>
  <rights>Copyright Reid McKenzie, 2026. All rights reserved.</rights>
  
  <entry>
    <title>Shelving; Building a Datalog for fun! and profit?</title>
    <link href="https://www.arrdem.com/2018/05/17/shelving_building_a_datalog/"/>
    <updated>2018-05-17T13:16:00+00:00</updated>
    <id>https://www.arrdem.com/2018/05/17/shelving_building_a_datalog</id>
    <content type="html">&lt;p&gt;&lt;em&gt;This post is my speaker notes from my May 3 &lt;a href=&quot;https://www.meetup.com/The-Bay-Area-Clojure-User-Group/&quot;&gt;SF Clojure&lt;/a&gt; talk &lt;a href=&quot;https://youtu.be/U4ckAGtv_OI&quot;&gt;(video)&lt;/a&gt; on building &lt;a href=&quot;https://github.com/arrdem/shelving&quot;&gt;Shelving&lt;/a&gt;, a toy Datalog implementation&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;databases&quot;&gt;Databases?&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;1960s; the first data stores. These early systems were very tightly coupled to the physical representation of data on tape. Difficult to use, develop, query and evolve.
    &lt;ul&gt;
      &lt;li&gt;CODASYL, a set of COBOL patterns for building data stores; essentially using doubly linked lists&lt;/li&gt;
      &lt;li&gt;IBM’s IMS which had a notion of hierarchical (nested) records and transactions&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;1969; E. F. Codd presents the “relational data model”&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;relational-data&quot;&gt;Relational data&lt;/h1&gt;

&lt;p&gt;Consider a bunch of data&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;::developer&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:given&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Reid&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
         &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:family&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;McKenzie&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
         &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:middle&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;douglas&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
         &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:signature&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Reid Douglas McKenzie&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:nicknames&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;arrdem&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;wayde&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;::developer&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:given&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Edsger&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
         &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:family&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Djikstra&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:nicknames&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ewd&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In a traditional (pre-relational) data model, you could imagine laying out a C-style struct in memory, where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; structure is mashed into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;developer&lt;/code&gt; structure at known byte offsets from the start of the record.
Or perhaps the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;developer&lt;/code&gt; structure references a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; by its tape offset and has a length tagged array of nicknames trailing behind it.&lt;/p&gt;

&lt;p&gt;The core insight of the relational data model is that we can define “joins” between data structures.
But we need to take a couple steps here first.&lt;/p&gt;

&lt;p&gt;Remember that maps are sequences of keys and values.
So to take one of the examples above,&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;::developer&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:given&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Edsger&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:family&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Djikstra&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:nicknames&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ewd&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; &amp;lt;=&amp;gt; under maps are k/v sequences&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;::developer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:given&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Edsger&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
         &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:family&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Djikstra&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:nicknames&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ewd&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; &amp;lt;=&amp;gt; under kv -&amp;gt; relational tuple decomp.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;::developer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:nickname&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ewd&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:given&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Edsger&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:family&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Djikstra&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We can also project maps to tagged tuples and back if we have some agreement on the order of the fields.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;::demo1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:foo&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:bar&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; &amp;lt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;::demo1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; under {0 :type 1 :foo 2 :bar}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally, having projected maps (records) to tuples, we can display many tuples as a table where columns are tuple entries and rows are whole tuples.
I mention this only for completeness, as rows and columns are common terms of use and I want to be complete here.&lt;/p&gt;

&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th scope=&quot;col&quot;&gt;foo&lt;/th&gt;
&lt;th scope=&quot;col&quot;&gt;bar&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Okay so we’ve got some data isomorphisms. What of it?&lt;/p&gt;

&lt;p&gt;Well the relational algebra is defined in terms of ordered, untagged tuples.&lt;/p&gt;

&lt;p&gt;Traditionally data stores didn’t include their field identifiers in the storage implementation as an obvious space optimization.&lt;/p&gt;

&lt;p&gt;That’s it.
That’s the relational data model - projecting flat structures to relatable tuple units.&lt;/p&gt;

&lt;h2 id=&quot;operating-with-tuples&quot;&gt;Operating with Tuples&lt;/h2&gt;

&lt;p&gt;The relational algebra defines a couple operations on tuples, or to be more precise sets of tuples.
There are your obvious set theoretic operators - &lt;em&gt;union&lt;/em&gt;, &lt;em&gt;intersection&lt;/em&gt; and &lt;em&gt;difference&lt;/em&gt;, and there’s three more.&lt;/p&gt;

&lt;h3 id=&quot;cartesian-product&quot;&gt;&lt;em&gt;cartesian product&lt;/em&gt;&lt;/h3&gt;

&lt;p&gt;let R, S be tuple sets ∀r∈R,∀s∈S, r+s ∈ RxS&lt;/p&gt;

&lt;p&gt;Ex. {(1,) (2,)} x {(3,) (4,)}
=&amp;gt; {(1, 3,) (1, 4,) (2, 3,) (2, 4,)}&lt;/p&gt;

&lt;h3 id=&quot;projection-select-keys&quot;&gt;&lt;em&gt;projection&lt;/em&gt; (select keys)&lt;/h3&gt;

&lt;p&gt;Projection is bettern known as select-keys.
It’s an operator for selecting some subset of all the tuples in a tuple space.
For instance if we have R defined as&lt;/p&gt;

&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th scope=&quot;col&quot;&gt;A&lt;/th&gt;
&lt;th scope=&quot;col&quot;&gt;B&lt;/th&gt;
&lt;th scope=&quot;col&quot;&gt;C&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;a&lt;/td&gt;
&lt;td&gt;b&lt;/td&gt;
&lt;td&gt;c&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;d&lt;/td&gt;
&lt;td&gt;a&lt;/td&gt;
&lt;td&gt;f&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;c&lt;/td&gt;
&lt;td&gt;b&lt;/td&gt;
&lt;td&gt;d&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;π₍a,b₎(R) would be the space of tuples from R excluding the C column -&lt;/p&gt;

&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;

&lt;thead&gt;
&lt;tr&gt;
&lt;th scope=&quot;col&quot;&gt;A&lt;/th&gt;
&lt;th scope=&quot;col&quot;&gt;B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;a&lt;/td&gt;
&lt;td&gt;b&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;d&lt;/td&gt;
&lt;td&gt;a&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;c&lt;/td&gt;
&lt;td&gt;b&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&quot;selection&quot;&gt;&lt;em&gt;selection&lt;/em&gt;&lt;a id=&quot;sec-3-1-3&quot; name=&quot;sec-3-1-3&quot;&gt;&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Where &lt;em&gt;projection&lt;/em&gt; selects elements from tuples, &lt;em&gt;selection&lt;/em&gt; selects tuples from sets of tuples.
I dislike the naming here, but I’m going with the original.&lt;/p&gt;

&lt;p&gt;To recycle the example R from above,&lt;/p&gt;

&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th scope=&quot;col&quot;&gt;A&lt;/th&gt;
&lt;th scope=&quot;col&quot;&gt;B&lt;/th&gt;
&lt;th scope=&quot;col&quot;&gt;C&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;a&lt;/td&gt;
&lt;td&gt;b&lt;/td&gt;
&lt;td&gt;c&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;d&lt;/td&gt;
&lt;td&gt;a&lt;/td&gt;
&lt;td&gt;f&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;c&lt;/td&gt;
&lt;td&gt;b&lt;/td&gt;
&lt;td&gt;d&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;σ₍B=b₎(R) - select where B=b over R would be&lt;/p&gt;

&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th scope=&quot;col&quot;&gt;A&lt;/th&gt;
&lt;th scope=&quot;col&quot;&gt;B&lt;/th&gt;
&lt;th scope=&quot;col&quot;&gt;C&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;a&lt;/td&gt;
&lt;td&gt;b&lt;/td&gt;
&lt;td&gt;c&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;joins&quot;&gt;Joins&lt;/h2&gt;

&lt;p&gt;Finally given the above operators, we can define the most famous one(s), &lt;em&gt;join&lt;/em&gt; and &lt;em&gt;semijoin&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;join-rs&quot;&gt;&lt;em&gt;join&lt;/em&gt; (R⋈S)&lt;/h3&gt;

&lt;p&gt;The (natural) join of two tuple sets is the subset of the set RxS where any fields COMMON to both r∈R and s∈S are “equal”.&lt;/p&gt;

&lt;p&gt;Consider some tables, R&lt;/p&gt;

&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th scope=&quot;col&quot;&gt;A&lt;/th&gt;
&lt;th scope=&quot;col&quot;&gt;B&lt;/th&gt;
&lt;th scope=&quot;col&quot;&gt;C&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;a&lt;/td&gt;
&lt;td&gt;b&lt;/td&gt;
&lt;td&gt;c&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;d&lt;/td&gt;
&lt;td&gt;e&lt;/td&gt;
&lt;td&gt;f&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;and S,&lt;/p&gt;

&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th scope=&quot;col&quot;&gt;A&lt;/th&gt;
&lt;th scope=&quot;col&quot;&gt;D&lt;/th&gt;
&lt;th scope=&quot;col&quot;&gt;E&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;a&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;d&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;We then have R⋈S to be&lt;/p&gt;

&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th scope=&quot;col&quot;&gt;A&lt;/th&gt;
&lt;th scope=&quot;col&quot;&gt;B&lt;/th&gt;
&lt;th scope=&quot;col&quot;&gt;C&lt;/th&gt;
&lt;th scope=&quot;col&quot;&gt;D&lt;/th&gt;
&lt;th scope=&quot;col&quot;&gt;E&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;a&lt;/td&gt;
&lt;td&gt;b&lt;/td&gt;
&lt;td&gt;c&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;d&lt;/td&gt;
&lt;td&gt;e&lt;/td&gt;
&lt;td&gt;f&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&quot;semijoin&quot;&gt;&lt;em&gt;semijoin&lt;/em&gt;&lt;/h3&gt;

&lt;p&gt;This is a slightly restricted form of join - you can think of it as the join on some particular column.
For instance, if R and S had several overlapping columns, the (natural) join operation joins by all of them.
For instance we may want to have several relations between two tables - and consequently leave open the possibility of several different joins.&lt;/p&gt;

&lt;p&gt;In general when talking about joins for the rest of this presentation I’ll be talking about natural joins over tables designed for only overlapping field so the natural join and the semijoin collapse.&lt;/p&gt;

&lt;h1 id=&quot;enter-datalog&quot;&gt;Enter Datalog&lt;/h1&gt;

&lt;p&gt;Codd’s relational calculus as we’ve gone through is a formulation of how to view data and data storage in terms of timeless, placeless algebraic operations.
Like the Lambda Calculus or “Maxwell’s Laws of Software” as Kay has described the original Lisp formulation, it provides a convenient generic substrate for building up operational abstractions.
It’s the basis for entire families of query systems which have come since.&lt;/p&gt;

&lt;p&gt;Which is precisely what makes Datalog interesting!
Datalog is almost a direct implementation of the relational calculus, along with some insights from logic programming.
Unfortunately, this also means that it’s difficult to give a precise definiton of what datalog &lt;em&gt;is&lt;/em&gt;.
Like lisp, it’s simple enough that there are decades worth of implementations, re-implementations, experimental features and papers.&lt;/p&gt;

&lt;p&gt;Traditionally, Datalog and Prolog share a fair bit of notation so we’ll start there.&lt;/p&gt;

&lt;p&gt;In traditional Datalog as in Prolog, “facts” are declared with a notation like this.
This particular code is in &lt;a href=&quot;http://souffle-lang.org/&quot;&gt;Souffle&lt;/a&gt; a Datalog dialect, which happened to have an Emacs mode.
This is the example I’ll be trying to focus on going forwards.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;State(&quot;Alaska&quot;)
State(&quot;Arizona&quot;)
State(&quot;Arkansas&quot;)

City(&quot;Juneau&quot;, &quot;Alaska&quot;)
City(&quot;Phoenix&quot;, &quot;Arizona&quot;)
City(&quot;Little Rock&quot;, &quot;Arkansas&quot;)

Population(&quot;Juneau&quot;, 2018, 32756)
Population(&quot;Pheonix&quot;, 2018, 1.615e6)
Population(&quot;Little Rock&quot;, 2018, 198541)

Capital(&quot;Juneau&quot;)
Capital(&quot;Phoenix&quot;)
Capital(&quot;Little Rock&quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Each one of these lines defines a tuple in the datalog “database”.
The notation is recognizable from Prolog, and is mostly agreed upon.&lt;/p&gt;

&lt;p&gt;Datalog also has rules, also recognizable from logic programming.
Rules describe sets of tuples in terms of either other rules or sets of tuples.
For instance&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;CapitalOf(?city, ?state) :- State(?state), City(?city, ?state), Capital(?city).
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is a rule which defines the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CapitalOf&lt;/code&gt; relation in terms of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;State&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;City&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Capital&lt;/code&gt; tuple sets.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CapitalOf&lt;/code&gt; rule can itself be directly evaluated to produce a set of “solutions” as we’d expect.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;?city&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;?state&lt;/code&gt; are logic variables, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;?-&lt;/code&gt; prefix convention being taken from Datomic.&lt;/p&gt;

&lt;p&gt;That’s really all there is to “common” datalog.
Rules with set intersection/join semantics.&lt;/p&gt;

&lt;h2 id=&quot;extensions&quot;&gt;Extensions&lt;/h2&gt;

&lt;p&gt;Because Datalog is so minimal (which makes it attractive to implement) it’s not particularly useful.
Like Scheme, it can be a bit of a hair shirt.
Most Datalog implementations have several extensions to the fundimental tuple and rule system.&lt;/p&gt;

&lt;h3 id=&quot;recursive-rules&quot;&gt;Recursive rules!&lt;/h3&gt;

&lt;p&gt;Support for recursive rules is one very interesting extension.
Given recursive rules, we could use a recursive Datalog to model network connectivity graphs &lt;a href=&quot;http://web.cs.ucdavis.edu/~green/papers/sigmod906t-huang-slides.pdf&quot;&gt;(1)&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Reachable(?s, ?d) :- Link(?s, ?d).
Reachable(?s, ?d) :- Link(?s, ?z), Reachable(?z, ?d).
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This rule defines reachability in terms of either there existing a link between two points in a graph, or there existing a link between the source point and some intermediate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Z&lt;/code&gt; which is recursively reachable to the destination point.&lt;/p&gt;

&lt;p&gt;The trouble is that implementing recursive rules efficiently is difficult although possible.
Lots of fun research material here!&lt;/p&gt;

&lt;h3 id=&quot;negation&quot;&gt;Negation!&lt;/h3&gt;

&lt;p&gt;You’ll notice that basic Datalog doesn’t support negation of any kind, unless “positively” stated in the form of some kind of “not” rule.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;TwoHopLink(?s, ?d) :- Link(?s, ?z), Link(?z, ?d), ! Link(?s, ?d).
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s quite common for databases to make the &lt;em&gt;closed world assumption&lt;/em&gt; - that is all possible relevant data exists within the database.
This sort of makes sense if you think of your tuple database as a subset of the tuples in the world.
All it takes is one counter-example to invalidate your query response if suddenly a negated tuple becomes visible.&lt;/p&gt;

&lt;h3 id=&quot;incremental-queries--differentiability&quot;&gt;Incremental queries / differentiability!&lt;/h3&gt;

&lt;p&gt;Datalog is set-oriented!
It doesn’t have a concept of deletion or any aggregation operators such as ordering which require realizing an entire result set.
This means that it’s possible to “differentiate” a Datalog query and evaluate it over a stream of incomming tuples because no possible new tuple (without negation at least) will invalidate the previous result(s).&lt;/p&gt;

&lt;p&gt;This creates the possibility of using Datalog to do things like describe application views over incremental update streams.&lt;/p&gt;

&lt;h3 id=&quot;eventual-consistency--distributed-data-storage&quot;&gt;Eventual consistency / distributed data storage!&lt;/h3&gt;

&lt;p&gt;Sets form a monoid under merge - no information can ever be lost.
This creates the possibility of building distributed data storage and query answering systems which are naturally consistent and don’t have the locking / transaction ordering problems of traditional place oriented data stores.&lt;/p&gt;

&lt;h1 id=&quot;the-yak&quot;&gt;The Yak&lt;/h1&gt;

&lt;p&gt;Okay. So I went and build a Datalog.&lt;/p&gt;

&lt;p&gt;Why? Because I wanted to store documentation, and other data.&lt;/p&gt;

&lt;h2 id=&quot;95-theses&quot;&gt;95 Theses&lt;/h2&gt;

&lt;p&gt;Who’s ready for my resident malcontent bit?&lt;/p&gt;

&lt;h3 id=&quot;grimoire&quot;&gt;Grimoire&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://conj.io&quot;&gt;Grimoire&lt;/a&gt; has a custom backing data store - &lt;a href=&quot;http://github.com/clojure-grimoire/lib-grimoire&quot;&gt;lib-grimoire&lt;/a&gt; - which provides a pretty good model for talking about Clojure and ClojureScript’s code structure and documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/clojure-grimoire/lib-grimoire#things&quot;&gt;https://github.com/clojure-grimoire/lib-grimoire#things&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;lib-grimoire was originally designed to abstract over concrete storage implementations, making it possible to build tools which generated or consumed Grimoire data stores.
And that purpose it has served admirably for me.
Unfortunately looking at my experiences onboarding contributors it’s clearly been a stumbling block and the current Grimoire codebase doesn’t respect the storage layer abstraction;
there are lots of places where Grimoire makes assumptions about how the backing store is structured because I’ve only ever had one.&lt;/p&gt;

&lt;h3 id=&quot;grenada&quot;&gt;Grenada&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/clj-grenada/grenada-spec&quot;&gt;https://github.com/clj-grenada/grenada-spec&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In 2015 I helped mentor Richard Moehn on his Grenada project.
The idea with the project was to take a broad view of the Clojure ecosystem and try to develop a “documentation as data” convention which could be used to pack documentation, examples and other content separately from source code - and particularly to enable 3rdparty documenters like myself to create packages for artifacts we don’t control (core, contrib libraries).
The data format Richard came up with never caught on I think because the scope of the project was just the data format not developing a suite of tools to consume it.&lt;/p&gt;

&lt;p&gt;What was interesting about Grenada is that it tried to talk about schemas, and provide a general framework for talking about the annotations provided in a single piece of metadata rather than relying on a hard-coded schema the way Grimoire did.&lt;/p&gt;

&lt;h3 id=&quot;cljdoc&quot;&gt;cljdoc&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/martinklepsch/cljdoc&quot;&gt;https://github.com/martinklepsch/cljdoc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In talking to Martin about cljdoc and some other next generation
tools, the concept of docs as data has re-surfaced again. Core’s
documentation remains utterly atrocious, and a consistent gripe of
the community yearly survey over survey.&lt;/p&gt;

&lt;p&gt;Documentation for core is higher hit rate than documentation for any other single library, so documenting core and some parts of contrib is a good way to get traction and add value for a new tool or suite thereof.&lt;/p&gt;

&lt;h2 id=&quot;prior-art&quot;&gt;Prior art&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Datomic is closed source&lt;/li&gt;
  &lt;li&gt;Lots of prior art with no persistence model
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://github.com/clojure/core.logic&quot;&gt;clojure.core.logic&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://github.com/tonsky/datascript&quot;&gt;datascript&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://github.com/alandipert/intension&quot;&gt;intension&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/replikativ/datahike&quot;&gt;Datahike&lt;/a&gt; is married to a particular storage model&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can bolt persistence ala carte onto most of the above with transit or just use edn, but then your serialization isn’t incremental at all.&lt;/p&gt;

&lt;p&gt;Building things is fun!&lt;/p&gt;

&lt;h2 id=&quot;design-goals&quot;&gt;Design goals&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Must lend itself to some sort of “merge” of many stores
    &lt;ul&gt;
      &lt;li&gt;Point reads&lt;/li&gt;
      &lt;li&gt;Keyspace scans&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Must have a self-descriptive schema which is sane under merges / overlays&lt;/li&gt;
  &lt;li&gt;Must be built atop a meaningful storage abstraction&lt;/li&gt;
  &lt;li&gt;Design for embedding inside applications first, no server&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;building-a-datalog&quot;&gt;Building a Datalog&lt;/h1&gt;

&lt;h2 id=&quot;storage-models&quot;&gt;Storage models!&lt;/h2&gt;

&lt;p&gt;Okay lets settle on an example that we can get right and refine some.&lt;/p&gt;

&lt;p&gt;Take a step back - Datalog is really all about sets, and relating a set of sets of tuples to itself.
What’s the simplest possible implementation of a set that can work?
An append only write log!&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[[:state &quot;Alaska&quot;]
 [:state &quot;Arizona&quot;]
 [:state &quot;Arkansas&quot;]
 [:city &quot;Juneau&quot; &quot;Alaska&quot;]
 [:city &quot;Pheonix&quot; &quot;Arizona&quot;]
 ...]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Scans are easy - you just iterate the entire thing.&lt;/p&gt;

&lt;p&gt;Writes are easy - you just append to one end of the entire thing.&lt;/p&gt;

&lt;p&gt;Upserts don’t exist, because we have set semantics so either you insert a straight duplicate which doesn’t violate set semantics or you add a new element.&lt;/p&gt;

&lt;p&gt;Reads are a bit of a mess, because you have to do a whole scan, but that’s tolerable.
Correct is more important than performant for a first pass!&lt;/p&gt;

&lt;h2 id=&quot;schemas&quot;&gt;Schemas!&lt;/h2&gt;

&lt;p&gt;So this sort of “sequence of tuples” thing is how &lt;a href=&quot;https://github.com/clojure/core.logic/blob/master/src/main/clojure/clojure/core/logic/pldb.clj&quot;&gt;core.logic.pldb&lt;/a&gt; works.
It maintains a map of sequences of tuples, keyed by the tuple “name” so that scans can at least be restricted to single tuple “spaces”.&lt;/p&gt;

&lt;p&gt;Anyone here think that truely unstructured data is a good thing?&lt;/p&gt;

&lt;p&gt;Yeah I didn’t think so.&lt;/p&gt;

&lt;p&gt;Years ago I did a project - spitfire - based on pldb.
It was a sketch at a game engine which would load data files for a the Warmachine table top game pieces and provide with a rules quick reference and ultimately I hoped a full simulation to play against.&lt;/p&gt;

&lt;p&gt;As with most tabletop war games, play proceeds by executing a clock, and repeatedly consulting tables of properties describing each model.
Which we recognize as database query.&lt;/p&gt;

&lt;p&gt;Spitfire used pldb to try and solve the data query problem, and I found that it was quite awkward to write to in large part because it was really easy to mess up the tuples you put into pldb.
There was no schema system to save you if you messed up your column count somewhere.
I &lt;a href=&quot;https://git.arrdem.com/?p=arrdem/spitfire.git;a=blob;f=src/main/clj/spitfire/pldb.clj;h=9f9894ccf81e6644e737d2eb026451ad49e6d2f6;hb=HEAD&quot;&gt;built one&lt;/a&gt;, but its ergonomics weren’t great.&lt;/p&gt;

&lt;p&gt;Since then, we got &lt;a href=&quot;https://github.com/clojure/spec.alpha&quot;&gt;clojure.spec(.alpha)&lt;/a&gt; which enables us to talk about the shape and requirements on data structures.
Spec is designed for talking about data in a forwards compatible way, unlike traditional type systems which intentionally introduce brittleness to enable evolution.&lt;/p&gt;

&lt;p&gt;While this may or may not be an appropriate trade-off for application development, it’s a pretty great trade-off for persisted data and schemas on persisted, iterated data!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/arrdem/shelving#schemas&quot;&gt;https://github.com/arrdem/shelving#schemas&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Values (sha512 hash identity &lt;a href=&quot;https://github.com/replikativ/hasch&quot;&gt;(hasch is excellent)&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Records (place identity)&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;s/def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;string?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;s/def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo.state/type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;s/def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/state&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;s/keys&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:req-un&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo.state/type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;-&amp;gt;state&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/state,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;s/def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/state&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;string?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;s/def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo.city/type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/city&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;s/def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/city&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;s/keys&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:req-un&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo.city/type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;-&amp;gt;city&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/city,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:state&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;s/def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;string?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;s/def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo.capital/type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/capital&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;s/def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/capital&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;s/keys&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:req-un&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo.capital/type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;-&amp;gt;capital&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/capital,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;*schema&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sh/empty-schema&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sh/value-spec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sh/value-spec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/city&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sh/value-spec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/capital&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sh/automatic-rels&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; lazy demo&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;writing&quot;&gt;Writing!&lt;/h2&gt;

&lt;p&gt;#‘shelving.core/put!&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Recursively walk spec structure
    &lt;ul&gt;
      &lt;li&gt;depth first&lt;/li&gt;
      &lt;li&gt;spec s/conform equivalent&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Generate content hashes for every tuple&lt;/li&gt;
  &lt;li&gt;Recursively insert every tuple (skipping dupes)&lt;/li&gt;
  &lt;li&gt;Insert the topmost parent record with either with a content hash ID or a generated ID depending on record/value semantics.&lt;/li&gt;
  &lt;li&gt;Create schema entries in the db if automatic schemas are on and the target schema/spec doesn’t exist in the db.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Okay so lets throw some data in -&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;*conn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sh/open&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;MapShelf&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;*schema&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/tmp/demo.edn&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
               &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:load&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
               &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:flush-after-write&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; #&apos;*conn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;*conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;doseq&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;city&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Alaska&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Juneau&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;city&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Arizona&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Pheonix&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;city&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Arkansas&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Little Rock&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sh/put-spec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/city&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;doseq&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;capital&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Juneau&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;capital&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Pheonix&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;capital&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Little Rock&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sh/put-spec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/capital&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;doseq&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;state&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Alaska&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;state&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Arizona&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;state&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Arkansas&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sh/put-spec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/state&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; nil&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;schema-migrations&quot;&gt;Schema migrations!&lt;/h3&gt;

&lt;p&gt;Can be supported automatically, if we’re just adding more stuff!&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Let the user compute the proposed new schema&lt;/li&gt;
  &lt;li&gt;Check compatibility&lt;/li&gt;
  &lt;li&gt;Insert into the backing store if there are no problems&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;query-parsing&quot;&gt;Query parsing!&lt;/h2&gt;

&lt;p&gt;Shelving does the same thing as most of the other Clojure datalogs and rips off Datomic’s datalog DSL.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sh/q&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;*conn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:find&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?state&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:in&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?city&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:where&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?_0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/city&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?city&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?_0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/city&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo.city/state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?_1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/capital&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?city&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]])&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is defined to have the same “meaning” (query evaluation) as&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sh/q&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;*conn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:find&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:in&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?city&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:where&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?_0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/city&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?city&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?_0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/city&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo.city/state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?_1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/capital&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:demo/name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?city&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;How can we achieve this?
Let alone test it reasonably?&lt;/p&gt;

&lt;p&gt;Spec to the rescue once again!
src/test/clj/shelving/parser&lt;sub&gt;test&lt;/sub&gt;.clj conform/unform “normal form” round-trip testing!&lt;/p&gt;

&lt;p&gt;Spec’s normal form can also be used as the “parser” for the query compiler!&lt;/p&gt;

&lt;h2 id=&quot;query-planning&quot;&gt;Query planning!&lt;/h2&gt;

&lt;p&gt;Traditional SQL query planning is based around optimizing disk I/O, typically by trying to do windowed scans or range order scans which respect the I/O characteristics of spinning disks.&lt;/p&gt;

&lt;p&gt;This is below the abstractive level of Shelving!&lt;/p&gt;

&lt;p&gt;Keys are (abstractly) unsorted, and all we have to program against is a write log anyway!
For a purely naive implementation we really can’t do anything interesting, we’re stuck in an O(lvars) scan bottom.&lt;/p&gt;

&lt;p&gt;Lets say we added indices - maps from ids of values of a spec to IDs of values of other specs they relate to.
Suddenly query planning becomes interesting.
We still have to do scans of relations, but we can restrict ourselves to talking about subscans based on relates-to information.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Take all lvars&lt;/li&gt;
  &lt;li&gt;Infer spec information from annotations &amp;amp; rels&lt;/li&gt;
  &lt;li&gt;Topsort lvars&lt;/li&gt;
  &lt;li&gt;Emit state-map -&amp;gt; [state-map] transducers &amp;amp; filters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;TODO:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Planning using spec cardinality information&lt;/li&gt;
  &lt;li&gt;Simultaneous scans (rank-sort vs topsort)&lt;/li&gt;
  &lt;li&gt;Blocked scans for cache locality&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;goodies&quot;&gt;Goodies&lt;/h2&gt;

&lt;h3 id=&quot;api-management&quot;&gt;API management!&lt;a id=&quot;sec-6-6-1&quot; name=&quot;sec-6-6-1&quot;&gt;&lt;/a&gt;&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;shelving.core is the intentional API for users&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;shelving.impl is the implementer’s API&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;import-vars &lt;a href=&quot;https://github.com/ztellman/potemkin/blob/master/src/potemkin/namespaces.clj#L77&quot;&gt;https://github.com/ztellman/potemkin/blob/master/src/potemkin/namespaces.clj#L77&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;documentation-generation&quot;&gt;Documentation generation!&lt;/h3&gt;

&lt;p&gt;Covered &lt;a href=&quot;/2018/02/26/docs_sketches/&quot;&gt;previously on the blog&lt;/a&gt; - I wrote a custom markdown generator and updater to help me keep my docstrings as the documentation source of truth, and update the markdown files in the repo by inserting appropriate content from docstrings when it changes.&lt;/p&gt;

&lt;h1 id=&quot;more-fun-still-to-be-had&quot;&gt;More fun still to be had&lt;/h1&gt;

&lt;p&gt;What makes Datalog really interesting is that among the many extensions which have been proposed is support for recursive rules.&lt;/p&gt;

&lt;h2 id=&quot;negation-1&quot;&gt;Negation!&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Really easy to bolt onto the parser, or enable as a query language flag&lt;/li&gt;
  &lt;li&gt;Doesn’t invalidate any of the current stream/filter semantics&lt;/li&gt;
  &lt;li&gt;Closed world assumption, which most databases happily make&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;recursive-rules-1&quot;&gt;Recursive rules!&lt;/h2&gt;

&lt;h2 id=&quot;more-backends&quot;&gt;More backends!&lt;/h2&gt;

&lt;h2 id=&quot;transactions&quot;&gt;Transactions!&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Local write logs as views of the post-transaction state&lt;/li&gt;
  &lt;li&gt;transact! writes an entire local write log all-or-nothing&lt;/li&gt;
  &lt;li&gt;server? optimistic locking? consensus / consistency issues&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;ergonomics&quot;&gt;Ergonomics!&lt;/h2&gt;

&lt;p&gt;The query DSL wound up super verbose unless you realy leverage the inferencer :c&lt;/p&gt;

&lt;h2 id=&quot;actually-replacing-grimoire&quot;&gt;Actually replacing Grimoire…&lt;a id=&quot;sec-7-6&quot; name=&quot;sec-7-6&quot;&gt;&lt;/a&gt;&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Should have just used a SQL ;) but this has been educational&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Docs Sketches</title>
    <link href="https://www.arrdem.com/2018/02/26/docs_sketches/"/>
    <updated>2018-02-26T06:18:00+00:00</updated>
    <id>https://www.arrdem.com/2018/02/26/docs_sketches</id>
    <content type="html">&lt;p&gt;At present I’m working on developing &lt;a href=&quot;https://github.com/arrdem/shelving&quot;&gt;Shelving&lt;/a&gt;, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.spec(.alpha)&lt;/code&gt; driven storage layer with a Datalog subset query language.
Ultimately, I want it to be an appropriate storage and query system for other project of mine like &lt;a href=&quot;https://github.com/arrdem/stacks&quot;&gt;Stacks&lt;/a&gt; and another major version of Grimoire.&lt;/p&gt;

&lt;p&gt;In building out this tool, I’ve been trying to be mindful of what I’ve built and how I’m communicating it.
What documentation have I written?
Is there a clear narrative for this component?
Am I capturing the reason I’m making these decisions and the examples that motivated me to come here?&lt;/p&gt;

&lt;p&gt;Writing good docs is really hard, doubly so when you’re trying to write documentation largely in docstrings.
Docs you write in the docstrings drift rapidly from docs written elsewhere.
The only surefire way I’ve come up with to keep the two in sync is to consider your docstrings to be authoritative and export them to other media.
So I wanted a tool for that.&lt;/p&gt;

&lt;p&gt;Another major problem is documentation organization.
In Clojure, namespaces have &lt;a href=&quot;https://github.com/ztellman/potemkin#import-vars&quot;&gt;long known limitations&lt;/a&gt; as the unit of structure for your API.
Clojure’s lack of support for circular references between namespaces and the need to use explicit forward declarations lead to large namespaces whose order reflects the dependency graph of the artifact not perhaps the intentional API or relative importance of its members.
In my first iterations of shelving, I was trying to just use a large &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.core&lt;/code&gt; namespace rather than maintain separate namespaces.
I wanted a tool that would let me take a large API namespace and break its documentation up into small subsections which had conceptual relationships.&lt;/p&gt;

&lt;p&gt;The result of these two needs is the following script, which I used for a while to generate the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docs/&lt;/code&gt; tree of the shelving repo.
To work around the issues of having a large, non-logical &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.core&lt;/code&gt; namespace, I annotated vars with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^:categories #{}&lt;/code&gt; metadata.
This allowed me to build up and maintain a logical partitioning of my large namespace into logical components.&lt;/p&gt;

&lt;p&gt;Documentation files are generated by opening an existing file, truncating any previously generated API docs in that category out, and appending newly generated docs to it.
This allows me to have Eg.
a Markdown title, some commentary, examples and what have you, then automatically splat the somewhat formatted and source linked docs for the relevant category at the end after that header.&lt;/p&gt;

&lt;p&gt;I won’t say the results are good.
But they beat the heck out of not having any docs at all.
Mainly they succeeded in being easier to browse, cross-check and consequently made copy editing docstrings much easier.&lt;/p&gt;

&lt;p&gt;With the introduction of distinct “user” and “implementer” APIs to Shelving which happen to share some vars, this categorization is no longer so clear cut.
Some docs now belong in one place, some in multiple places.
This is an inadequate tool for capturing those concerns.
Also it still sorts symbols by line numbers when generating docs 😞&lt;/p&gt;

&lt;p&gt;So I’ll be building another doodle, but thought that this one was worth capturing before I do.&lt;/p&gt;

&lt;p&gt;Some sample output -&lt;/p&gt;

&lt;center&gt;&amp;lt;a href=https://github.com/arrdem/shelving/blob/04c8bbe22f6736f8852f3e8c9775c0159c94a12e/docs/basic.md&amp;gt;&lt;img src=&quot;/images/2018-02-25-224125_1475x907_scrot.png&quot; /&gt;&amp;lt;/a&amp;gt;&lt;/center&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile-docs&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A quick hack for building the doc tree based on `^:category` data.&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:require&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shelving.core&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:as&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clojure.java.io&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:as&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clojure.string&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:as&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category-map&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;::sh/basic&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;io/file&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;docs/basic.md&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;::sh/schema&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;io/file&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;docs/schema.md&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;::sh/rel&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;io/file&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;docs/rel.md&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;::sh/util&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;io/file&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;docs/helpers.md&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;::sh/query&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;io/file&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;docs/queries.md&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;::sh/spec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;io/file&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;docs/spec.md&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;::sh/walk&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;io/file&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;docs/walk.md&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)})&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ensure-trailing-newline&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;if-not&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.endsWith&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;relativize-path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;str/replace&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.getCanonicalPath&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;io/file&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile-docs&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category-map&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vars&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nss&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:reload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;if-not&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;instance?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clojure.lang.Namespace&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                         &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;the-ns&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sym&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;maybe-var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ns-publics&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:when&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;instance?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clojure.lang.Var&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;maybe-var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
               &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;maybe-var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;groupings&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;group-by&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:categories&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;groupings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;doseq&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;groupings&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category-file&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category-map&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:when&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;           &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category-file&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;               &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sort-by&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; FIXME: better scoring heuristic?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:keys&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;categories&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arglists&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stability&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                              &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:as&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var-meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;with-open&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;io/writer&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category-file&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:append&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;binding&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;*out*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;## [%s/%s](%s#L%s)\n&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ns-name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.ns&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.sym&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;relativize-path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;doseq&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arglists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot; - `%s`\n&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cons&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.sym&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stability&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:stability/unstable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;**UNSTABLE**: This API will probably change in the future\n\n&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ensure-trailing-newline&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                       &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;str/replace&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;(?&amp;lt;!\n)\n[\s&amp;amp;&amp;amp;[^\n\r]]+&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                       &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;str/replace&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;\n\n[\s&amp;amp;&amp;amp;[^\n\r]]+&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;\n\n&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recompile-docs&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category-map&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;doseq&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_cat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category-map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buff&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;slurp&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;truncated&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;str/replace&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buff&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;(?s)\n+##.++&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;\n\n&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;spit&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;truncated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;compile-docs&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category-map&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recompile-docs!&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Entry point suitable for a lein alias. Usable for automating doc rebuilding.&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;recompile-docs&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category-map&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                  &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shelving.core&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shelving.query&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shelving.spec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shelving.spec.walk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; In lein:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; :profiles {:dev {:aliases {&quot;build-docs&quot; [&quot;run&quot; &quot;-m&quot; &quot;compile-docs/recompile-docs!&quot;]}}}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; Works best with lein-auto to keep your doctree fresh&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;^d&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Intermediate Abstraction</title>
    <link href="https://www.arrdem.com/2017/07/27/intermediate-abstraction/"/>
    <updated>2017-07-27T00:00:00+00:00</updated>
    <id>https://www.arrdem.com/2017/07/27/intermediate-abstraction</id>
    <content type="html">&lt;p&gt;This talk was presented at the &lt;a href=&quot;https://www.meetup.com/The-Bay-Area-Clojure-User-Group&quot;&gt;Bay Area Clojure&lt;/a&gt; meetup, hosted by &lt;a href=&quot;https://www.fundingcircle.com/us/&quot;&gt;Funding Circle&lt;/a&gt;. These notes are presented here with thanks to the organizers and attendees.&lt;/p&gt;

&lt;div id=&quot;table-of-contents&quot;&gt;
&lt;h2&gt;Table of Contents&lt;/h2&gt;
&lt;div id=&quot;text-table-of-contents&quot;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#sec-1&quot;&gt;1. Preface&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sec-2&quot;&gt;2. Context&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sec-3&quot;&gt;3. Complexity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sec-4&quot;&gt;4. Abstraction&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#sec-4-1&quot;&gt;4.1. Examples of Abstraction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sec-4-2&quot;&gt;4.2. Limits of Abstractions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sec-4-3&quot;&gt;4.3. Inheritance, Composition &amp;amp; Re-use&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sec-4-4&quot;&gt;4.4. Naming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sec-4-5&quot;&gt;4.5. Achieving Abstraction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sec-4-6&quot;&gt;4.6. Utility Is Contextual&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sec-5&quot;&gt;5. Performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#sec-6&quot;&gt;6. Fin: Purism&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-sec-1&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-1&quot;&gt;&lt;span class=&quot;section-number-2&quot;&gt;1&lt;/span&gt; Preface&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-1&quot;&gt;
&lt;p&gt;
Hey folks! For those of you who don&apos;t know me, I&apos;m Reid McKenzie. I&apos;ve been writing Clojure on and
off for about four years now. These days I work for Twitter as a Site Reliability Engineer.
&lt;/p&gt;

&lt;p&gt;
Twitter Site Reliability is really small. We&apos;re not even 150 engineers tasked with ensuring that
all the infrastructure and services required to support the business stay online. It&apos;s clear that
as the business continues to grow, we in SRE can&apos;t continue be traditional reactive system
operators. We must be software engineers developing automation and designing systems capable of
intervention-less recovery.
&lt;/p&gt;

&lt;p&gt;
Achieving quality in software engineering means we must develop an understanding of how to
exercise our powers of abstraction, and that we appreciate and managing the complexity with which
we are surrounded. This talk presents some formal and philosophical concepts intended to elevate
the ways we approach problem solving which will I hope be useful to you.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-sec-2&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-2&quot;&gt;&lt;span class=&quot;section-number-2&quot;&gt;2&lt;/span&gt; Context&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-2&quot;&gt;
&lt;p&gt;
Programming is a young profession all things told.
&lt;/p&gt;

&lt;p&gt;
If we trace the roots of our profession to Lovelace as she is the first to have written of a
machine which could be used for general purpose and perhaps program or modify itself then our
profession such as it is dates to the 1830s. Just shy of the two century mark.
&lt;/p&gt;

&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;


&lt;colgroup&gt;
&lt;col  class=&quot;right&quot; /&gt;

&lt;col  class=&quot;left&quot; /&gt;

&lt;col  class=&quot;left&quot; /&gt;
&lt;/colgroup&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th scope=&quot;col&quot; class=&quot;right&quot;&gt;Date&lt;/th&gt;
&lt;th scope=&quot;col&quot; class=&quot;left&quot;&gt;Who&lt;/th&gt;
&lt;th scope=&quot;col&quot; class=&quot;left&quot;&gt;Event&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class=&quot;right&quot;&gt;1928&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Hilbert&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Entscheidungsproblem&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;right&quot;&gt;1933&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Godel, Herbrand&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;μ-recursive functions (simple arithmetic)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;right&quot;&gt;1936&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Church&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;λ calculus, models Entscheidungsproblem with reduction&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;right&quot;&gt;&amp;#xa0;&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Turing&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Turing machine, models Entscheidungsproblem with halting&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;right&quot;&gt;1941&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Zuse&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;First programmable, general purpose computer&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;right&quot;&gt;194{5,6}&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Von Neumann&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Von Neumann single memory architecture&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;right&quot;&gt;&amp;#x2026;&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;&amp;#xa0;&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;&amp;#xa0;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;right&quot;&gt;1950&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;USGOV, Banks&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Computers become common place for census &amp;amp; data processing&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;right&quot;&gt;1956&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Bell Labs&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Transistors are invented&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;right&quot;&gt;1970&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;IBM, Commodore&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;First transistorized PCs come to the market&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;right&quot;&gt;1976&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Wozniak&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Apple I&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;right&quot;&gt;&amp;#x2026;&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;&amp;#xa0;&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;&amp;#xa0;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;right&quot;&gt;2017&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;&amp;#xa0;&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Us, here, today, floundering variously&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;
Computation as a science is grounded in the concepts of evaluation and analysis. The science is in
the theoretical limits of what a machine could do. The question of how to achieve something on a
given machine is the province of software engineering.
&lt;/p&gt;

&lt;p&gt;
Software engineering is a younger discipline still. We&apos;ve only really been writing software since
the &apos;50s (Excepting Lovelace&apos;s programs which never had a machine), so call it 60 years of
recognizable programming during the course of which huge shifts have occurred in the industry.
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
In retrospect one can only wonder that those first machines worked at all, at least sometimes. The
overwhelming problem was to get and keep the machine in working order.
&lt;/p&gt;

&lt;p&gt;
&amp;#x2013; Dijkstra &quot;The Humble Programmer&quot; &lt;a href=&quot;https://www.cs.utexas.edu/~EWD/transcriptions/EWD03xx/EWD340.html&quot;&gt;EWD340&lt;/a&gt; (1972)
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
The problem with software engineering is, well, for the most part we never get to do it. The
profession of programming as adopted in industry is rooted in the now seemingly long tradition of
just getting the machine to work at all and then &quot;debugging&quot; it which has carried since the first
programs in the &apos;50s. The operations tradition from which SRE programs are usually developed is
particularly guilty of this.
&lt;/p&gt;

&lt;p&gt;
Rather than have a concrete body of science to reference and with which to inform decisions, every
working programmer develops an aesthetic taste for what seems to them like the right way to solve
problems; what kept the computer or systems of computers in working order and solved the problem
best. The problem with taste is that it is deeply subjective. It reflects our personal experiences
in education, what javascript frameworks we&apos;ve played with on the side and how we did it at
$LASTJOB. When tastes conflict, they can&apos;t inform each-other except with great difficulty because
there&apos;s no underlying theory which can be used to relate and moderate them.
&lt;/p&gt;

&lt;p&gt;
The question is how do we earn the E in our titles. And the answer is not to continue artistically
operating the systems we have or continuing to do what seems to work. We must develop and
communicate formal understandings for the tools and tactics we use.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-sec-3&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-3&quot;&gt;&lt;span class=&quot;section-number-2&quot;&gt;3&lt;/span&gt; Complexity&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-3&quot;&gt;
&lt;blockquote&gt;
&lt;p&gt;
&lt;b&gt;Simple&lt;/b&gt;; Simplex; To have but a single strand, to be one.
&lt;/p&gt;

&lt;p&gt;
&lt;b&gt;Complex&lt;/b&gt;; To be woven from several strands.
&lt;/p&gt;

&lt;p&gt;
&lt;b&gt;Complect&lt;/b&gt; (archaic); To plait together.
&lt;/p&gt;

&lt;p&gt;
&lt;b&gt;Easy&lt;/b&gt;; from the French &lt;b&gt;alsie&lt;/b&gt; meaning comfortable and tranquil. Not difficult, requiring no
great labor or effort.
&lt;/p&gt;

&lt;p&gt;
&amp;#x2013; Rich Hickey &lt;a href=&quot;https://www.infoq.com/presentations/Simple-Made-Easy&quot;&gt;&quot;Simple Made Easy&quot;&lt;/a&gt; (2012)
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
Often, we miss-use simple to mean easy.
&lt;/p&gt;

&lt;p&gt;
Ideally, we want to write code which is both simple and easy. This requires that we be concious
both of complexity and of ergonomics. However we only rarely have objective critera for these two
critical dimensions.
&lt;/p&gt;

&lt;p&gt;
The fact that a perfectly reasonable engineer may consider a tool sufficient and easy while
another may just as reasonably a tool baroque and overbearing is a core motivator for this
talk. Sharing an objective metric of simplicity clarifies otherwise subjective questions and
enables us to agree upon measurements of solution quality.
&lt;/p&gt;

&lt;p&gt;
Thankfully there is prior art on the subject of attempting to estimate complexity. Karl Popper&apos;s
&lt;a href=&quot;https://en.wikipedia.org/wiki/The_Logic_of_Scientific_Discovery&quot;&gt;Logic of Scientific Discovery&lt;/a&gt; builds a framework of formal logic with which to formalize the
scientific process itself.
&lt;/p&gt;

&lt;p&gt;
Popper bases his project upon &lt;i&gt;falsifiability&lt;/i&gt; and &lt;i&gt;corroboration&lt;/i&gt; through experiment. A
hypothesis for Popper is a formal statement which is &lt;i&gt;falsifiable&lt;/i&gt; because it implies testable
outcomes. An experiment cannot confirm a hypothesis, because to do so would imply that no other
experiment (state of the entire universe) could possibly falsify the hypothesis. However, we can
fail to falsify the claims of the hypothesis, and we can even show that the experiment produced a
state which &lt;i&gt;corroborates&lt;/i&gt; the prediction(s) of the hypothesis.
&lt;/p&gt;

&lt;p&gt;
Popper proposes that the complexity of a theory can be measured by reasoning about the set of
states of the universe which would falsify the theory. These sets can be related to each other and
relative complexity measured by establishing implication and subset relations, but this is far
from enough to be a really working rule of measurement. Comparing infinities (sets of states of
the universe) is hardly intuitive.
&lt;/p&gt;

&lt;p&gt;
The good news is that there are ways we can do this!
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;https://en.wikipedia.org/wiki/Cyclomatic_complexity&quot;&gt;Cyclomatic complexity (McCabe)&lt;/a&gt; measures the number of control paths through a program. This
approach works, and even gives an obvious heuristic for recognizing complexity in the simple
number of branches but it is uni-dimensional and doesn&apos;t capture the fact that our programs have
and manipulate state.
&lt;/p&gt;

&lt;p&gt;
Dataflow complexity is a related family of metrics which try to measure the possibility space of
the data (state) in a program. Unfortunately, beyond giving an intuition for the idea that
complexity grows with the memory footprint of a program there&apos;s not an efficient way to quantify
or relate this kind of complexity.
&lt;/p&gt;

&lt;p&gt;
We get into this mess of having to count states in order to talk about complexity because both of
these complexity estimators use the model of a Von Neumann finite state machine machine whose
states cannot easily be related to each other.
&lt;/p&gt;

&lt;p&gt;
If we go back to Popper, if we have two logical reduction statements P and Q, we can &lt;span class=&quot;underline&quot;&gt;estimate&lt;/span&gt;
their relative complexity by simply comparing the number of degrees of freedom of each
expression. Likewise using the μ calculus (simple arithmetic and reduction) or the λ calculus
(function application and reduction) we instantly regain the property that we can understand the
complexity of an expression or program merely by looking at the number of terms it involves and
counting them.
&lt;/p&gt;

&lt;p&gt;
This intuition is supported by cyclomatic complexity and dataflow complexity metrics because (for
programs which halt under reduction) the complexity of a program written with reduction is, well,
one. Each datum and program point is unique and occurs only once.
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
λx.xx λx.xx
&lt;/p&gt;

&lt;p&gt;
→ λx.xx λx.xx
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
That this &lt;span class=&quot;underline&quot;&gt;must&lt;/span&gt; be an &lt;span class=&quot;underline&quot;&gt;estimate&lt;/span&gt;, not a precise metric as a divergent combinator such as ω will
mess this whole thing right up. But per the halting problem there&apos;s not much we can do here so if
we accept (as we must) that this is an incomplete analysis and restrict ourselves to the domain of
terminating expressions we can still get a lot of utility out of this rule of thumb.
&lt;/p&gt;

&lt;p&gt;
Now, we don&apos;t write purely functional programs, and when we do write programs which use functional
tools and abstractions there&apos;s still global state lying around because we compute on Turing
machines not graph reduction engines (those are really hard to build). How do we estimate
complexity for real programs then?
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
It has been suggested that there is some kind of law of nature telling us that the amount of
intellectual effort needed grows with the square of program length. But, thank goodness, no one
has been able to prove this law. And this is because it need not be true.
&lt;/p&gt;

&lt;p&gt;
&amp;#x2013; EWD, &quot;The Humble Programmer&quot;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
There is room for reasonable disagreement here, but I&apos;d propose a very simple heuristic for
estimating complexity; the product of the following properties of a program or program segment.
&lt;/p&gt;

&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;1 + Number of input parameters
&lt;/li&gt;
&lt;li&gt;1 + Number of branches
&lt;/li&gt;
&lt;li&gt;1 + Number of back-edges
&lt;/li&gt;
&lt;li&gt;1 + Amount of REACHED CAPTURED state which is accessed (maybe 2x cost of a parameter)
&lt;/li&gt;
&lt;li&gt;1 + Amount of REACHED CAPTURED state which is modified (maybe more than 2x the cost of a parameter)
&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coll&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lazy-seq&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cons&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rest&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
That is, a function which accepts more parameters and takes many branches using them is more
complex than a function which accepts a function and a few parameters as parameters and merely
delegates to the argument function. The real branching behavior of such an applied higher order
function may be complex, but the function itself is simple. It captures little state and does
little directly.
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Attempts to log a message, either directly or via an agent; does not check if
  the level is enabled.
  For performance reasons, an agent will only be used when invoked within a
  running transaction, and only for logging levels specified by
  *tx-agent-levels*. This allows those entries to only be written once the
  transaction commits, and are discarded if it is retried or aborted.  As
  corollary, other levels (e.g., :debug, :error) will be written even from
  failed transactions though at the cost of repeat messages during retries.
  One can override the above by setting *force* to :direct or :agent; all
  subsequent writes will be direct or via an agent, respectively.&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;throwable&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;case&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;*force*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:agent&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:direct&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;and&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;clojure.lang.LockingTransaction/isRunning&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;*tx-agent-levels*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;send-off&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;*logging-agent*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;impl/write!&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;throwable&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;impl/write!&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;throwable&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;declare&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:dynamic&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;*logger-factory*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defmacro&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Evaluates and logs a message only if the specified level is enabled. See log*
  for more details.&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger-factory&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger-ns&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;throwable&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;impl/get-logger&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger-factory&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger-ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;impl/enabled?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;throwable&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
An expression which does little, but does so using values which it draws from global state such as
a configuration value may still be simple, but it is not so simple as a function which accepts
that same configuration structure directly as a parameter. This complexity becomes evident when
testing, as a test for the simple function merely requires calling the simple function with the
appropriate configuration value where testing the globally configured function requires
manipulating the state of the entire application so that the shared mutable configuration state
conforms to the tests requirements.
&lt;/p&gt;

&lt;p&gt;
We can see that the log macro is actually quite complex becuase it &lt;i&gt;reaches&lt;/i&gt; a significant amount
of global state despite the fact that the log macro itself doesn&apos;t actually do that much. The log
macro has to check in a global mutable registry of namespaces to logger implementations for a
logger, check the whether that logger is enabled and then do the logging, potentially
manufacturing a new logger using the factory from global state if it has to.
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mongo!&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Creates a Mongo object and sets the default database.
      Does not support replica sets, and will be deprecated in future
      releases.  Please use &apos;make-connection&apos; in combination with
      &apos;with-mongo&apos; or &apos;set-connection!&apos; instead.
       Keyword arguments include:
       :host -&amp;gt; defaults to localhost
       :port -&amp;gt; defaults to 27017
       :db   -&amp;gt; defaults to nil (you&apos;ll have to set it anyway, might as well do it now.)&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:arglists&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:db&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:host&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;localhost&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:port&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;27017&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:keys&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:or&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;localhost&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;27017&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set-connection!&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;make-connection&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:host&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:port&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
A function which changes state may be complex compared to a function which produces no effects and
returns a value, but it introduces far more whole program complexity if global state is modified
especially if it is modified many times.
&lt;/p&gt;

&lt;p&gt;
This supports the intuition that perhaps sorting a list received as an argument in place doesn&apos;t
add so much whole program complexity because the effect is restricted in scope to the caller and
wherever the list to be modified was sourced from whereas reading and manipulating the &lt;code&gt;ERRNO&lt;/code&gt;
global value in a C program may directly impact any number of other program behaviors. Such
modification defeats referential transparency, and forces us to use sequential logics at the level
of the whole program to achieve understanding.
&lt;/p&gt;

&lt;p&gt;
We use multiplication rather than addition to reflect that really what we&apos;re trying to approximate
is the VOLUME of a multi-dimensional state space, which is measured by the product of the length
of the sides, not their sum.
&lt;/p&gt;

&lt;p&gt;
With apologies to Dijkstra, I note that it is quite possible for a program&apos;s complexity by this
metric alone to grow at least in proportion to the square of the program&apos;s length. However there&apos;s
also still plenty of room at the bottom for simple programs to achieve near-linear complexity
growth.
&lt;/p&gt;

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://dl.acm.org/citation.cfm?id=1313821&quot;&gt;Software Structure Metrics Based on Information Flow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://wwwusers.di.uniroma1.it/~lpara/LETTURE/backus.pdf&quot;&gt;Backus77 &quot;Can programming be liberated from the Von Neumann Style&quot;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Essential_complexity&quot;&gt;Essential Complexity (McCabe)&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-sec-4&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-4&quot;&gt;&lt;span class=&quot;section-number-2&quot;&gt;4&lt;/span&gt; Abstraction&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-4&quot;&gt;
&lt;blockquote&gt;
&lt;p&gt;
We all know that the only mental tool by means of which a very finite piece of reasoning can cover
a myriad cases is called “abstraction”; as a result the effective exploitation of his powers of
abstraction must be regarded as one of the most vital activities of a competent programmer. In
this connection it might be worth-while to point out that the purpose of abstracting is not to be
vague, but to create a new semantic level in which one can be absolutely precise.
&lt;/p&gt;

&lt;p&gt;
&amp;#x2013; EWD, &quot;The Humble Programmer&quot;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
What is an abstraction?
&lt;/p&gt;

&lt;p&gt;
Abstractions can be considered to consist of a &lt;i&gt;model&lt;/i&gt;, &lt;i&gt;interface&lt;/i&gt; and an &lt;i&gt;environment&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;
The &lt;i&gt;model&lt;/i&gt; of an abstraction is the set of operational semantics which it exposes to a user. For
instance a queue or channel as an abstraction provides the model that a user writes to it and a
consumer reads from it. Reads may be in some order such as FIFO or LIFO, or un-ordered with
respect to writes. A bounded queue may provide the additional semantics that, if the writer
outpaces the reader it can only get so far ahead before the queue put operation blocks the
writer. A &lt;a href=&quot;http://ipfs.io/ipfs/QmVYSfZrsLFYQR5W186n1djFPY9A4EBnb9z3ZQLpjhupiS&quot;&gt;Concurrent Sequantial Processes&lt;/a&gt; queue provides the operational semantics that when a
write occurs the reader is awakened and so only the reader or the writer is ever operating at
once.
&lt;/p&gt;

&lt;p&gt;
The &lt;i&gt;interface&lt;/i&gt; is the set of operations which the abstraction provides to the user. For instance
the channel can have elements enqueued and dequeued. Perhaps the queue can also be closed at one
end, denoting that either the source or the destination is finished whereupon the other end will
eventually (or immediately) also close.
&lt;/p&gt;

&lt;p&gt;
Abstractions don&apos;t exist in a vacuum. They have expectations which they may demand of the outside
world (externalities) such as restrictions on how they are used or in what context they are
employed. Everything that the model omits is ultimately an assumption about the &lt;i&gt;environment&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;
It may be helpful to note that the &lt;i&gt;environment&lt;/i&gt; is the dual of the &lt;i&gt;model&lt;/i&gt;. Anything that is not
part of the &lt;i&gt;model&lt;/i&gt; must be part of the &lt;i&gt;environment&lt;/i&gt;, and by growing the &lt;i&gt;model&lt;/i&gt; we can shrink
dependency on the &lt;i&gt;environment&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;
This is deeply significant, in that mismatch between environments and reality results in friction
for the user, and tends to be resolved not by abandoning the abstraction but by humans adapting to
the restrictions imposed upon them by inadequate tools.
&lt;/p&gt;

&lt;p&gt;
Abstractions may be compared - one said to be simpler than the other - on the basis of the size of
the &lt;i&gt;model&lt;/i&gt;, &lt;i&gt;interface&lt;/i&gt; and expectations imposed on the &lt;i&gt;environment&lt;/i&gt;. The &lt;i&gt;model&lt;/i&gt; after all is a
space of states, the &lt;i&gt;interface&lt;/i&gt; a set of functions above, and externalities may be either a set
of propositions or a space of states as the two are equivalent.
&lt;/p&gt;

&lt;p&gt;
The ergonomics of abstractions may also be compared - one said to be more consistent than the
other - on the basis of the consistency of the names and structure of the abstraction&apos;s interface
with each-other and predictability of the relationship between the interface, the model and its
externalities.
&lt;/p&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-sec-4-1&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;sec-4-1&quot;&gt;&lt;span class=&quot;section-number-3&quot;&gt;4.1&lt;/span&gt; Examples of Abstraction&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-4-1&quot;&gt;
&lt;p&gt;
Per the Dijkstra quote above, abstraction is all about changing or choosing semantics. I&apos;ll give
a treatment of linguistic abstraction shortly, but by naming things we can build semantic
levels - languages - which convey what we want.
&lt;/p&gt;

&lt;p&gt;
We can abstract over control flow by using higher order functions which provide for instance
conditional execution giving us a tool with which we can talk about for instance conditionally
applying a transformation.
&lt;/p&gt;

&lt;p&gt;
We can abstract over values by choosing types or decomposing values into their components, using
aggregate logical values and references which enable us to refer to parts of our data.
&lt;/p&gt;

&lt;p&gt;
However it is not abstractive to perform computation. When we &quot;compute&quot; (reduce) an expression,
we discard information irrecoverably. For instance an average is not meaningfully an abstraction
over a time series. It is a datom, the product of some other irrecoverable data under a
function. By computing this new value, we&apos;ve given ourselves an aggregate view which no longer
carries the same semantics and cannot meaningfully be considered to be equivalent to its source.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-sec-4-2&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;sec-4-2&quot;&gt;&lt;span class=&quot;section-number-3&quot;&gt;4.2&lt;/span&gt; Limits of Abstractions&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-4-2&quot;&gt;
&lt;p&gt;
Unfortunately, abstractions do have limits.
&lt;/p&gt;

&lt;p&gt;
Traditional types which you may be familiar with, your &lt;code&gt;int&lt;/code&gt; and &lt;code&gt;char&lt;/code&gt;, are really just raw
presentations of what the physical machine can do with a given value. Rarely however do these
presentations of machine capabilities map to the senses which are meaningful to us. They are the
poorest possible of abstractions - none at all.
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdint.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#define EVAL(...) printf(&quot;%s: %d\n&quot;, #__VA_ARGS__, __VA_ARGS__)
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;EVAL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int32_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;EVAL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int32_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)));&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;EVAL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int32_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;pre class=&quot;example&quot;&gt;
(int32_t)(1&lt;&lt;31)-1: 2147483647
(int32_t)(~(1&lt;&lt;31)): 2147483647
(int32_t)(1&lt;&lt;31): -2147483648
&lt;/pre&gt;

&lt;p&gt;
How many times in Java have you actually wanted precisely a value with 2&lt;sup&gt;32&lt;/sup&gt; states of which 2&lt;sup&gt;31&lt;/sup&gt;-1
states are said to represent positive numbers, 2&lt;sup&gt;31&lt;/sup&gt; states represent negative numbers and the
zeroed bit string represents &amp;#x2026; zero. And arithmetic wraps around, flipping the sign should we
excede the bounds of [-2&lt;sup&gt;31&lt;/sup&gt;, &amp;#x2026;, +2&lt;sup&gt;31&lt;/sup&gt;-1]. We also know that while we have a vector of bits
&amp;#x2026; somewhere and one of them is a sign, and we can count on the 32nd bit being the sign we can&apos;t
actually make endianness assumptions about the bytes in our integer(s). So much for bitmasking
tricks.
&lt;/p&gt;

&lt;p&gt;
This &lt;i&gt;abstraction&lt;/i&gt; of an &lt;code&gt;int&lt;/code&gt; type provides addition, subtraction, multiplication, division,
absolute value and of course comparison. All of which we associate with the concept of an
integer. Furthermore this abstraction supplies, by specifying &lt;i&gt;model&lt;/i&gt; of the machine
representation, all the operations we customarily associate with a vector of bits - and, or, xor,
shifting, inversion.
&lt;/p&gt;

&lt;p&gt;
If all we want is addition and comparison, the rest of this behavior is not just semantic
baggage, it adds complexity. What if I want to count to 2&lt;sup&gt;31&lt;/sup&gt;? I have to be aware that this
abstraction&apos;s &lt;i&gt;model&lt;/i&gt; says I&apos;ll get -2&lt;sup&gt;31&lt;/sup&gt;+1, not the value I expect. Or perhaps an out of band
signal that an IntegerOverflowException occurred, which constitutes another cross-cutting concern
because now the abstraction implies a system of exceptions with which I must be familiar.
&lt;/p&gt;

&lt;p&gt;
For a large domain of problems, this abstraction does well enough. However we must be constantly
aware of its failure modes. We as professionals bear a constant cognitive cost in conforming
ourselves to the limits which this &lt;i&gt;abstraction&lt;/i&gt; presents to us.
&lt;/p&gt;

&lt;p&gt;
It should be recognized here that Haskell, Lisp(s) and other languages which provide arbitrary
precision integer types out of the box capture a simpler programming model by default. A &lt;i&gt;model&lt;/i&gt;
which has more implementation complexity to be sure and consequently expects more of the
&lt;i&gt;environment&lt;/i&gt; for instance the presence of a memory manager but the &lt;i&gt;interface&lt;/i&gt; is smaller and
less thorny.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-sec-4-3&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;sec-4-3&quot;&gt;&lt;span class=&quot;section-number-3&quot;&gt;4.3&lt;/span&gt; Inheritance, Composition &amp;amp; Re-use&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-4-3&quot;&gt;
&lt;p&gt;
Software quality is defined first by solving the business needs of the here and now. If software
or strategy or any other tool doesn&apos;t do that, it&apos;s worthless. Software is a form of physical
capital in the same sense as a steam engine or a factory. A factory which can be re-tooled to
produce articles of a different design is more valuable than a factory which will require full
replacement should the product change. Likewise an engine or assembly line which must be
significantly reworked in order to add capacity or change task is less valuable than a design
which naturally features a pattern along which it can be changed without significant alteration.
&lt;/p&gt;

&lt;p&gt;
Object Oriented Programming (that is, programming via encapsulation and inheritance) promised
that it would improve among other things software reusability when it broke into the scene.
&lt;/p&gt;

&lt;p&gt;
The problem with inheritance as a strategy in practice is that any tool which wants to participate
in some abstraction is forced to conform to the expectations of the interface established by the
parent which the child wishes to participate in. The &lt;i&gt;interface&lt;/i&gt; must accumulate.
&lt;/p&gt;

&lt;p&gt;
Furthermore, reuse through inheritance has the problem of capturing mutable state. An extension or
wrapper class must be intimately familiar with the state of the class it wraps and the
expectations it may make. The &lt;i&gt;model&lt;/i&gt; accumulates.
&lt;/p&gt;

&lt;p&gt;
In &quot;Simple Made Easy&quot; Rich gave a good treatment of this, pointing out that code partitioning
doesn&apos;t imply decoupling and pointing to Interface Oriented Programming is the response to this
problem, because interfaces only bring with them their direct set of expectations.
&lt;/p&gt;

&lt;p&gt;
To be precise about what&apos;s happening here - the &lt;i&gt;model&lt;/i&gt; of inheritence oriented programming
forces us to accreet &lt;i&gt;interfaces&lt;/i&gt; and &lt;i&gt;externalities&lt;/i&gt;. Thankfully this is not an essential
property of abstraction, merely a property of this particular technique.
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mapcat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;colls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;colls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;colls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
When we take two abstractions and put them together, we say that we&apos;ve composed them. For instance
two functions compose together to make a third. The &lt;code&gt;map&lt;/code&gt; function composes with the &lt;code&gt;concatenate&lt;/code&gt;
function to give us &lt;code&gt;mapcat&lt;/code&gt;. &lt;code&gt;map&lt;/code&gt; lets us apply a function over many values, and &lt;code&gt;concat&lt;/code&gt;
allows us to join sequences together. We can thus define &lt;code&gt;mapcat&lt;/code&gt; to be a function which lets us
join the results of applying a function which produces sequences to many values. The composite
&lt;i&gt;model&lt;/i&gt; of &lt;code&gt;mapcat&lt;/code&gt; requires only the additional constraint that &lt;code&gt;f: a → [b]&lt;/code&gt;, that is the
function to be mapped produces results which can be concatenated.
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;evens&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;keep&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;even?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;%1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
We can build abstractions which have smaller interfaces. For instance if we take a function of a
configuration and a datom and we partially apply it with a configuration, we now have a fixed
function of a datom. Its model is smaller - we know how it will behave because we&apos;ve specified
whatever configuration(s) the larger base model depends on and the interface is smaller - it
consists only of the datom to manipulate.
&lt;/p&gt;

&lt;p&gt;
Building a small wrapper around a large Java API would be a good example of such a composite
abstraction with a smaller interface.
&lt;/p&gt;

&lt;p&gt;
We can also build composite abstractions which traverse the &lt;i&gt;model&lt;/i&gt; and &lt;i&gt;externality&lt;/i&gt;
trade-off. For instance we can build abstractions which simplify the set of &lt;i&gt;externalities&lt;/i&gt; by
providing input or state validation where previously we had unchecked expecatations. This expands
the model since now the expectations are explicitly modeled and checked. We can also reduce the
complexity of the model by choosing to make assumptions.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-sec-4-4&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;sec-4-4&quot;&gt;&lt;span class=&quot;section-number-3&quot;&gt;4.4&lt;/span&gt; Naming&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-4-4&quot;&gt;
&lt;p&gt;
Credit: Zachary Tellman, &lt;a href=&quot;https://leanpub.com/elementsofclojure&quot;&gt;Elements of Clojure (unreleased)&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
Linguistic abstraction in the form of naming is the most fundamental tool available to us as both
artisans and engineers.
&lt;/p&gt;

&lt;p&gt;
Names being the tools we use to understand our tools, choosing good names (whatever that means) is
of primary importance. But what characterizes a &quot;good&quot; name?
&lt;/p&gt;

&lt;p&gt;
Frege suggests that a name consists of three properties - the &lt;i&gt;sign&lt;/i&gt;, the textual representation
of the name, the &lt;i&gt;referent&lt;/i&gt; being the entity referred to by the &lt;i&gt;sign&lt;/i&gt;, and finally the &lt;i&gt;sense&lt;/i&gt;,
being the properties ascribed to the &lt;i&gt;referent&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;
The traditional example is that &lt;i&gt;Phosphorous&lt;/i&gt; (morning star) and &lt;i&gt;Hesperus&lt;/i&gt; (evening star) are
both Greek celestial bodies which we now understand to both name the planet &lt;i&gt;Venus&lt;/i&gt;. The &lt;i&gt;sign&lt;/i&gt;
and &lt;i&gt;referent&lt;/i&gt; are according to Frege insufficient to understand these two terms which are prima
facie synonyms because they don&apos;t actually interchange.
&lt;/p&gt;

&lt;p&gt;
A good name must satisfy two properties - it must be &lt;i&gt;narrow&lt;/i&gt; and &lt;i&gt;consistent&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;
A &lt;i&gt;narrow&lt;/i&gt; name excludes things it cannot represent; its &lt;i&gt;sense&lt;/i&gt; is only as broad as the context
of its use requires. For instance if the only expectation to be made of a &lt;i&gt;reference&lt;/i&gt; is that it
will be a mapping, then &lt;code&gt;map&lt;/code&gt; or its contraction &lt;code&gt;m&lt;/code&gt; is a perfectly acceptable name if that is
the only &lt;i&gt;sense&lt;/i&gt; in which the &lt;i&gt;referent&lt;/i&gt; is used.
&lt;/p&gt;

&lt;p&gt;
A &lt;i&gt;consistent&lt;/i&gt; name shares the same &lt;i&gt;sense&lt;/i&gt; for a &lt;i&gt;referent&lt;/i&gt; as is used for that &lt;i&gt;referent&lt;/i&gt; in
other related contexts. To continue the example of a mapping, to subsequently &lt;i&gt;sign&lt;/i&gt; the same
&lt;i&gt;referent&lt;/i&gt; as &lt;code&gt;dict&lt;/code&gt; elsewhere would be less than ideal both because it&apos;s a broader name which
implies a specific kind of mapping and thus no longer shares the same &lt;i&gt;sense&lt;/i&gt;. A simple mapping
&lt;code&gt;m&lt;/code&gt; may only imply &lt;code&gt;clojure.lang.ILookup&lt;/code&gt;, whereas &lt;code&gt;hashmap&lt;/code&gt; implies &lt;code&gt;java.util.HashMap&lt;/code&gt; and
side-effectful update. Naming and naming conventions are tremendously important in the context of
dynamically checked systems wherein names largely depend on their &lt;i&gt;sense&lt;/i&gt; to communicate the type
or at least intent of the use of the &lt;i&gt;referent&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;
Lets consider some examples (adapted from Zach&apos;s fine book)
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;c1&quot;&gt;;; This is a Very Bad expression.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; The left referent is very broad, when we clearly use it in a narrow sense. It&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; should be more narrowly named.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; The value we get out of our broad referent is named very narrowly. The single&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; string contains far too much sense.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;sol-jupiter-callisto&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; This is a better equivalent expression, because we communicate a more&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; appropriate sense for our previously over-broad sign, and we unpacked the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; previously overly precise key into a set of more general structures each of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; which communicates less sense.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get-in&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;starsystem&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;jupiter&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;callisto&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; Better yet capture the logical operation, the fact that Callisto is a moon of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; Jupiter is an assumption in all of the above expressions.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get-body-by-name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;callisto&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; It would also be better to be completely precise about the sense of the name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; Callisto by doing something like&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get-system&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;sol&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;     &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;; This communicates that we want to get a &quot;system&quot; named sol&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get-body&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;callisto&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;; And we care about the component &quot;body&quot; named callisto&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; This expression further communicates the sense that Callisto is a moon of Jupiter.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get-system&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;sol&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get-body&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;jupiter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get-moon&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;callisto&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; Both of these two latter expressions are better because more of the relevant&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; sense of the name callisto is captured explicitly, rather than being implied&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; upon or expected of the seemingly broad mapping referent.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-sec-4-5&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;sec-4-5&quot;&gt;&lt;span class=&quot;section-number-3&quot;&gt;4.5&lt;/span&gt; Achieving Abstraction&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-4-5&quot;&gt;
&lt;p&gt;
As suggested in the discussion of the &lt;i&gt;consistency&lt;/i&gt; of &lt;i&gt;signs&lt;/i&gt;, part of the problem here is that
we&apos;re forced by the tools we use to project our &lt;i&gt;sense&lt;/i&gt; directly upon the &lt;i&gt;sign&lt;/i&gt;.
&lt;/p&gt;

&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;


&lt;colgroup&gt;
&lt;col  class=&quot;left&quot; /&gt;

&lt;col  class=&quot;left&quot; /&gt;

&lt;col  class=&quot;left&quot; /&gt;
&lt;/colgroup&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th scope=&quot;col&quot; class=&quot;left&quot;&gt;Types: A heresy&lt;/th&gt;
&lt;th scope=&quot;col&quot; class=&quot;left&quot;&gt;static sense&lt;/th&gt;
&lt;th scope=&quot;col&quot; class=&quot;left&quot;&gt;dynamic sense&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class=&quot;left&quot;&gt;static dispatch&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Haskell, C, Java&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Java (class casting)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td class=&quot;left&quot;&gt;dynamic dispatch&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;C (dyn linking)&lt;/td&gt;
&lt;td class=&quot;left&quot;&gt;Smalltalk, Python, Ruby&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;
Static type systems provide a &lt;i&gt;model&lt;/i&gt; with which we can talk about the &lt;i&gt;sense&lt;/i&gt; we associate to a
name by capturing at least some of the &lt;i&gt;sense&lt;/i&gt; in which we intend to use the &lt;i&gt;referent&lt;/i&gt; as a type
and knowing that if we can determine a type (and the type must conform to a type of which we knew
ahead of time) then we can begin to understand the behavior of our systems through the lense of
the types we&apos;ve assigned to our data.
&lt;/p&gt;

&lt;p&gt;
Some systems allow us to use this information statically to check that at least some part of the
&lt;i&gt;sense&lt;/i&gt; or &lt;i&gt;type&lt;/i&gt; is consistently respected in the use of a &lt;i&gt;referent&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;
Some systems enable you to capture more &lt;i&gt;sense&lt;/i&gt; than others, by encoding the sense statically in
what we usually call a type.
&lt;/p&gt;

&lt;p&gt;
Type systems can be compared in terms of how much sense they enable you to capture, and how
difficult it is to do so.
&lt;/p&gt;

&lt;p&gt;
Lets say that we wanted to count up from zero, to continue the example of positive integers from
above. We could choose a &lt;i&gt;sign&lt;/i&gt; with which to reference our value which indicates that it&apos;s an
index such as the traditional &lt;code&gt;i&lt;/code&gt;, or &lt;code&gt;idx&lt;/code&gt; or even &lt;code&gt;index&lt;/code&gt; depending on individual taste. But
sometimes we want to play clever tricks with the fact that sometimes negative indexes are defined,
or we want to be tricky and reach back to some location &quot;before&quot; in memory where we&apos;re currently
indexed to and soforth. The choice of &lt;i&gt;sign&lt;/i&gt; implies only &lt;i&gt;sense&lt;/i&gt;, it cannot constrain the
&lt;i&gt;referent&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;
However, we can choose abstractions which let us do so. For instance, we could build an
abstraction which only allows us to capture ℕ, the natural or counting numbers.
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collections&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;namedtuple&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;functools&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total_ordering&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@total_ordering&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;namedtuple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])):&lt;/span&gt;
  &lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;A numeric value constricted to N (the counting numbers).&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__new__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isinstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ValueError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;N is constrained to [0, 1, ...)&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__new__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__int__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__add__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__sub__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__eq__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__lt__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
This isn&apos;t so different from the full Haskell implementation of &lt;a href=&quot;https://github.com/hanshoglund/positive/blob/master/src/Numeric/Positive.hs&quot;&gt;Numeric.Positive&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
There are techniques which can be used to try and capture more sense. This technique is best known
as &quot;smart constructors&quot;. Rather restrict the &lt;i&gt;sense&lt;/i&gt; to the &lt;i&gt;sign&lt;/i&gt;, we&apos;ve defined a type which can
only take on values conforming to our desired &lt;i&gt;sense&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;
The additional semantic restrictions we can impose on ourselves from the type free us from either
having to check the sense ourselves over and over again which is the most verbose and fragile
path, or from settling for the integer sense we get &quot;for free&quot; and hoping that it&apos;s enough.
&lt;/p&gt;

&lt;p&gt;
This tactic can be applied to any domain where we want to give a type to a subset of some other
space of values. For instance strings of a known format. It is just window dressing, but
frequently it&apos;s enough that we can approximate the semantics we actually want.
&lt;/p&gt;

&lt;p&gt;
To take another example, what if we were to try and make a type for a &lt;a href=&quot;https://en.wikipedia.org/wiki/SOA_Resource_Record&quot;&gt;Start of Authority (SOA)&lt;/a&gt;
version?  We could use a simple &lt;code&gt;string&lt;/code&gt;, after all that&apos;s what the SOA becomes when we lay it out
in a zone file, and the only requirements we have of an SOA is that it increase to define an
ordering among zone file versions.
&lt;/p&gt;

&lt;p&gt;
Generally however, strings (even constrianed strings!) should be avoided. Text is the least
structured form of data. Parsing is, even with the aid of parser combinators and regular
expressions, difficult and error prone. It&apos;s far better to use fully realized data representations
which can be rendered to strings than to keep data as a string and decode it.
&lt;/p&gt;

&lt;p&gt;
Which carries more semantic meaning - the string &quot;20170706001&quot;, or the tuple
&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collections&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;namedtuple&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scanf&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scanf&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# 3rdparty
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SOA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;namedtuple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;SOA&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;year&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;month&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;day&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])):&lt;/span&gt;
  &lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;A tuple capturing a DNS SOA format.&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;PATTERN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%04d%02d%02d%03d&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__new__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Decode a SOA string, returning a SOA tuple&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SOA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__new__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scanf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PATTERN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__str__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Encode this SOA as a string&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PATTERN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# self is an appropriate 4-tuple already
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SOA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;20170706001&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# SOA(year=2017, month=7, day=6, version=1)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;
The tuple can be rendered to and parsed from text as required, and above all it captures the sense
in which we use SOAs which leaving the SOA as a plain string does not. If strings are just passed
through and not manipulated, then perhaps it&apos;s acceptable to keep them represented as strings and
skip decoding but structures like this which capture more of the sense of our data should be
preferred.
&lt;/p&gt;

&lt;p&gt;
Unfortunately there&apos;s often lots of other sense we may care about - for instance that we have a
number within the index bounds of some structure or that there exists a record in the database
with an &lt;code&gt;id&lt;/code&gt; primary key of this value for any possible value. Checking these senses statically
may well be impossible. There could be a concurrent change to the database and a once valid
identifier becomes dangling and soforth.
&lt;/p&gt;

&lt;p&gt;
Static types in the Haskell sense of things &lt;span class=&quot;underline&quot;&gt;help&lt;/span&gt;, they allow you to capture &lt;span class=&quot;underline&quot;&gt;some&lt;/span&gt; of the
relevant sense - enough in my experience that software development may be &lt;i&gt;easier&lt;/i&gt; because the
type system helps you especially when you need to change abstractions but thanks to the
completeness theorem we know all too well that they can never check every property we may care
about.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-sec-4-6&quot; class=&quot;outline-3&quot;&gt;
&lt;h3 id=&quot;sec-4-6&quot;&gt;&lt;span class=&quot;section-number-3&quot;&gt;4.6&lt;/span&gt; Utility Is Contextual&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-4-6&quot;&gt;

&lt;div class=&quot;figure&quot;&gt;
&lt;p&gt;&lt;img src=&quot;http://socrates.arts.ubc.ca/wordpress/wp-content/uploads/2015/04/platos-cave.jpg&quot; alt=&quot;platos-cave.jpg&quot; /&gt;
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;
It&apos;s tempting to think that we can, through great skill or shear luck, discover perfect
abstractions; Platonic ideal or Martian crystalline forms of a concept which satisfy all our
needs for all time. The problem with this view is that different contexts have different
needs. Many objects may generate the same shadow on the wall of Plato&apos;s cave.
&lt;/p&gt;

&lt;p&gt;
For instance above I attacked the &quot;stock&quot; numeric abstractions which include hardware
implementation details, suggesting that arbitrary precision math is a better default. I stand by
that argument, but it must be recognized that there are occasions when we must make different
tradeoffs in choosing our models.
&lt;/p&gt;

&lt;p&gt;
Sometimes we need to interface with the machine. Sometimes we want to use (or author) bit
vectors. Sometimes we don&apos;t have a memory manager and can&apos;t afford truely arbitrary precision
arithmetic. Sometimes the performance degredation of operating on a &lt;code&gt;double&lt;/code&gt; floating point
number as opposed to a &lt;code&gt;single&lt;/code&gt; or &lt;code&gt;half&lt;/code&gt; width floating point number is meaningful and we must
make a choice to increase complexity and sacrifice ergonomics in the name of utility. That some
machine type is the shared &lt;i&gt;interface&lt;/i&gt; of some other abstraction and that the &lt;i&gt;externality&lt;/i&gt; of
the machine&apos;s particular wall time performance relate to our context changes what is appropriate.
&lt;/p&gt;

&lt;p&gt;
Just as we should exercise caution in choosing our names so that we don&apos;t choose overly &lt;i&gt;narrow&lt;/i&gt;
or &lt;i&gt;broad&lt;/i&gt; names, so we must exercise caution in choosing our abstractions. The simplest possible
abstraction with the fewest possible externalities may well not be the most appropriate to the
domain, and worse still a simple abstraction is not likely to lend itself to change. Like other
crystals, abstractions shatter or shear rather than bend from their natural shape.
&lt;/p&gt;

&lt;p&gt;
Coupling of abstractions - allowing the tools you choose to share externalities and to expect
one-another is dangerous because it means that even small deviation from the original
requirements and context may prove cause for significant change with rippling consequences for
your entire system.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-sec-5&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-5&quot;&gt;&lt;span class=&quot;section-number-2&quot;&gt;5&lt;/span&gt; Performance&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-5&quot;&gt;
&lt;blockquote&gt;
&lt;p&gt;
The greatest performance improvement of all is when a system goes from not-working to working.
&lt;/p&gt;

&lt;p&gt;
&amp;#x2013; Osterhaut &lt;a href=&quot;http://web.stanford.edu/~ouster/cgi-bin/sayings.php&quot;&gt;&quot;My Favorite Sayings&quot;&lt;/a&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
Performance and efficiency generally are factors in the measurement of how well a tool solves or
responds to the needs of the &quot;user&quot;, whether they be a person, business or other entity.
&lt;/p&gt;

&lt;p&gt;
A code breaking machine which can decode a daily message in 32 hours isn&apos;t sufficient. It can&apos;t
decode messages fast enough for them to be relevant. Such a machine is not useless, but it doesn&apos;t
solve the problem set for it adequately. Three such machines together will provide, at an 32 hour
delay each, the previous day&apos;s message and perhaps a fourth or even pairs of machines may be
supplied for reliability in order to provide a more-or less continuous feed of intelligence but it
would still be yesterday&apos;s data today and delivered at great cost.
&lt;/p&gt;

&lt;p&gt;
In this example we have an objective criterion of how much performance is &quot;enough&quot;. The cracking
machine must have a cracking rate of at least 1 msg per 24 hrs, and we have an objective
measurement that we&apos;re only able able to crack at the rate of 1 msg per 32 hrs.
&lt;/p&gt;

&lt;p&gt;
There are two primary approaches to achieving performance where it is required. The first approach
is to simply do less work - either by reducing the problem using algorithmic optimization, or by
reducing the size of inputs by firing customers or negotiating system scope. When optimization must
occur, algorithmic or organizational optimization should be by far preferred in the interest of
overall program simplicity with all its other virtues.
&lt;/p&gt;

&lt;p&gt;
The second approach is to tune what work must be done to better suit the machinery we use to do
it. This is what we usually mean when optimization comes up, although in general we should prefer
to find ways to simplify and reduce the problem.
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
Two opinions about programming date from those days. &amp;#x2026; The one opinion was that a really
competent programmer should be puzzle-minded and very fond of clever tricks; the other opinion was
that programming was nothing more than optimizing the efficiency of the computational process, in
one direction or the other.
&lt;/p&gt;

&lt;p&gt;
&amp;#x2013; EWD, &quot;The Humble Programmer&quot;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
To be clever means to be &quot;sharp&quot;, &quot;quick&quot; and &quot;skillful&quot;. The old English roots suggest a sense of
&quot;cutting&quot; and &quot;keenness&quot;. It would be cleverness to design a tool which does the difficult or
seemingly impossible within resource constraints by leveraging intimate knowledge of the system.
&lt;/p&gt;

&lt;p&gt;
This formulation of a &quot;clever trick&quot; implies that a really clever trick &lt;span class=&quot;underline&quot;&gt;must&lt;/span&gt; also have a high
complexity. This is the root of the trouble with optimizations of the second kind. Clever tricks
while perhaps relevant in the moment are in the long term likely to prove troublesome.
&lt;/p&gt;

&lt;p&gt;
Worse, clever tricks of this kind require specializing some part or all of your program so that it
reflects performance considerations. This has the particular negative consequence of meaning that
your code cannot be so simple and algorithmic anymore - it must be reflective of some state(s) or
trick(s) used to achieve acceptable performance because performance is now a crosscutting concern
which must be accounted for by your abstractions.
&lt;/p&gt;

&lt;p&gt;
Frequently, reasoning from first principles is not enough to produce fully optimized code. Modern
high performance sorting algorithms are absolutely fascinating, because while the algorithmic
complexity may suggest that provably optimal algorithms such as mergesort or quicksort should be
universally adopted it turns out there are frequently ways to cheat and do better. Modern
collections libraries use adaptive sorting strategies which benefit from existing sortedness in
the input collection and frequently contain multiple different sorting implementations which are
applied to different sizes of collection.
&lt;/p&gt;

&lt;p&gt;
Even apparently simple statements like &quot;doing two string concatenations will be slower than doing
one&quot; are impossible to evaluate without a real effort at profiling. The JVM among other platforms
recognize that string manipulation is &quot;expensive&quot; due to the need to resize and copy
buffers. However, both the Oracle JDK and OpenJDK actually include several optimizations which
detect code doing trivial string concatenations and silently replace it with equivalent code which
uses the StringBuilder class which delays buffer resizing as long as possible.
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
If you want fast, start with comprehensible. You can&apos;t make it fast if you can&apos;t change it.
&lt;/p&gt;

&lt;p&gt;
&amp;#x2013; Paul Phillips, &lt;a href=&quot;https://www.youtube.com/watch?v=TS1lpKBMkgg&quot;&gt;&quot;We&apos;re Doing It All Wrong&quot;&lt;/a&gt; (2013)
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
Unless there are known constraints, such as here the hard throughput requirement of a message a
day question of &quot;is it fast enough?&quot; and the statements &quot;this isn&apos;t performant&quot; or &quot;we need to do
this for performance&quot; are totally meaningless. Worse, they detract from the goal which should be
to ship a tool which serves a purpose and introduce artificial pressure to conform the choice of
abstractions to arbitrary false goals.
&lt;/p&gt;

&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://computers-are-fast.github.io/&quot;&gt;https://computers-are-fast.github.io/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://people.eecs.berkeley.edu/~rcs/research/interactive_latency.html&quot;&gt;https://people.eecs.berkeley.edu/~rcs/research/interactive_latency.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Amdahl&apos;s_law&quot;&gt;Amdahl&apos;s Law&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;outline-container-sec-6&quot; class=&quot;outline-2&quot;&gt;
&lt;h2 id=&quot;sec-6&quot;&gt;&lt;span class=&quot;section-number-2&quot;&gt;6&lt;/span&gt; Fin: Purism&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-6&quot;&gt;
&lt;p&gt;
Niklaus Wirth&apos;s work is notable superficially because Wirth is himself a prodigious hacker. He&apos;s
responsible for, among other projects, no fewer than five separate programming languages and two
operating systems. What&apos;s the trick? How does he do it?
&lt;/p&gt;

&lt;p&gt;
In the implementation of the Modula-2 compiler, Wirth and his students used two metrics to
estimate and track its quality over the course of its evolution. One was the simple line count of
the program - a poor proxy for complexity but a data point none the less. Another was the time
which it took the compiler to compile itself.
&lt;/p&gt;

&lt;p&gt;
One of Wirth&apos;s students implemented an elegant hash table backed by binary trees, for use in
mapping strings to symbols - to look up local variables and implement lexical scope. Doing so
introduced a new, complex datastructure, increased the line count of the compiler and added at
best no performance benefit for it turned out most scopes in real programs were small for which a
simple association list could be faster. Wirth ripped the hash table out.
&lt;/p&gt;

&lt;p&gt;
Wirth was also a great user of tools, such as &lt;a href=&quot;http://matt.might.net/articles/grammars-bnf-ebnf/&quot;&gt;Backus-Naur Form&lt;/a&gt; and parser generators for
expressing precisely the meaning which he wished to ascribe to a given set of symbols and the
notation which his languages should represent. Even in these, Wirth&apos;s ascetic attachment to
simplicity is clear - all of his languages are simple and can be efficiently implemented without
any clever tricks whatsoever.
&lt;/p&gt;

&lt;p&gt;
Simplicity and quality aren&apos;t properties which code or systems get by osmosis or by grant of the
gods. They are the product of deliberate effort by programmers to resist the entropic pressure
applied by reality and customer requirements on systems and to in spite of that pressure carve out
cohesive, appropriate abstractions which leave room for growth.
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
It would be equally absurd, then, to expect that in unjust, cowardly, and voluptuous action there
should be a mean, an excess, and a deficiency; for at that rate there would be a mean of excess
and of deficiency, an excess of excess, and a deficiency of deficiency. But as there is no excess
and deficiency of temperance and courage because what is intermediate is in a sense an extreme, so
too of the actions we have mentioned there is no mean nor any excess and deficiency, but however
they are done they are wrong; for in general there is neither a mean of excess and deficiency, nor
excess and deficiency of a mean.
&lt;/p&gt;

&lt;p&gt;
&amp;#x2013; Aristotle, &quot;Nichomachean Ethics&quot;, Book II, Ch. 6
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
In the &quot;Nichomachean Ethics&quot;, Aristotle (or rather his student Plato writing in his master&apos;s name)
develops a system of ethics on the basis that one must always choose the mean between excess and
deficiency.
&lt;/p&gt;

&lt;p&gt;
There is a fashion in the software community to be &quot;pragmatic&quot;. That is, to be tempered or
practical with respect to an attitude or policy. Unfortunately, if you temper temperance with an
added dose of reality, you no longer have &quot;pragmatism&quot;, you have a regression. Software as an
industry is built on an incrementalism of &quot;progress&quot; which is informed by experience but largely
unaware and often dismissive of the possibility space.
&lt;/p&gt;

&lt;p&gt;
Before we can claim to be pragmatic, we must have a vision of the perfection from which we turn
aside in practical interests. It is my opinion that the overwhelming majority of working
programmers are not conscious of what could be; of how higher order tools could help them; of how
the pains they feel are the fault of specific failures of their tools and are not essential.
&lt;/p&gt;

&lt;p&gt;
My goal with this talk was to share with you some of the philosophy and purism which I carry with
me and which I hope helps me to strive for more perfect solutions. I hope that it helps you too.
&lt;/p&gt;

&lt;p&gt;
Thanks.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  
  <entry>
    <title>Immutable Env Things</title>
    <link href="https://www.arrdem.com/2016/06/13/immutable_env_things/"/>
    <updated>2016-06-13T00:00:00+00:00</updated>
    <id>https://www.arrdem.com/2016/06/13/immutable_env_things</id>
    <content type="html">&lt;p&gt;As with some of my other posts, this was originally an email which turned into enough of a screed I
thought it would be of general interest and worth posting. Some op/ed material has been removed, but
the technical details are unaltered if not clarified.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;So here’s the rundown I’ve got so far on a lisp with immutable environments. I’m merely gonna sketch
at some stuff, because giving a full treatment would require dusting off and finishing a bunch of
stuff I came up with for Ox and put down again.&lt;/p&gt;

&lt;p&gt;I also threw out the &lt;a href=&quot;https://www.refheap.com/120294&quot;&gt;Haskell sketch&lt;/a&gt; I was dinking with because it
was just distracting from writing this :P&lt;/p&gt;

&lt;p&gt;So lets start from the top.&lt;/p&gt;

&lt;p&gt;Clojure is a form-at-a-time language which happens to support reading files of forms (or rather
Readers which produce textual representations of forms, where they come from is magical).&lt;/p&gt;

&lt;p&gt;Binding is achieved through a global, thread shared, transactional, mutable mapping from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Symbols&lt;/code&gt;
to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Namespaces&lt;/code&gt;, which are themselves transactional mappings from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Symbols&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vars&lt;/code&gt;, which are
themselves a triple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(QualifiedSymbol, Metadata, Binding)&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vars&lt;/code&gt; happen to also support dynamic
binding (pushing and popping), but this is less used. From here on out I’ll treat them simply as a
global mostly static binding mechanism, which is their primary use case anyway.&lt;/p&gt;

&lt;p&gt;Control and local bindings are achieved entirely using lambda/fn forms compiled to JVM methods,
produced by the opaque compiler as opaque IFn/AFn objects. Top level forms are compiled and executed
for effect by being wrapped in an anonymous &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(fn [] &amp;lt;form&amp;gt;)&lt;/code&gt; which can be blindly invoked by the
compiler to realize whatever effects the form may have.&lt;/p&gt;

&lt;p&gt;Circular dependencies are achieved via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt; indirection. A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt; is first created with no binding,
so that it can be referenced. With that environment binding, code which will depend on (call) the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;’s final bound value can be compiled since it just needs the target &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt; to exist in order to
compile. The depended on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt; may then be redefined, having both itself and its dependent visible
in the compilation context and so the two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt; bindings can be mutually recursive.&lt;/p&gt;

&lt;p&gt;While traditional and lispy, this approach has a number of problems which I’m sure I don’t need to
reiterate here. The goals of an immutable namespace system then should be to&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Make Namespaces the compilation unit rather than Forms&lt;/li&gt;
  &lt;li&gt;Make Namespaces reloadable (change imports/exports/aliases w/o system reboot)&lt;/li&gt;
  &lt;li&gt;Enable Namespace compilation to fail sanely&lt;/li&gt;
  &lt;li&gt;Enable refactoring/analysis&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The sketch of this I’ve been playing with is as follows:&lt;/p&gt;

&lt;p&gt;Lets assume an interpreter. If you can interpret you can compile as an implementation detail of eval
and interpretation is easier to implement initially.  Assume a reader. So we read a form, then we
have to evaluate it. Evaluation is first macroexpansion, then sequential evaluation of each
resulting form in the environment. Evaluation at the top level is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval Env Form -&amp;gt; Env&lt;/code&gt; (we discard
the result) which is fine. Because we aren’t really doing compilation, only interpretation,
Clojure’s tactic of having Vars and analyzing against Var bindings works 1:1. Create an unbound
symbol, analyze/bind against it, then add a binding later.&lt;/p&gt;

&lt;p&gt;The (global) environment structure I had in mind is pretty simple: one unqualified symbol names the
current namespace (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*ns*&lt;/code&gt;), a mapping exists from unqualified symbols to Namespaces.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Namespace&lt;/code&gt;s are essentially compilation contexts, and really just serve to immutably store the
alias mapping, import mapping, the mapping of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;s in the namespace to bindings, and a list of
the public &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;s/exports from the namespace.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;s are a fully qualified name, metadata and a value. That’s it.&lt;/p&gt;

&lt;p&gt;Compilation occurs at the namespace level. All the forms in a namespace are sequentially read and
evaluated in interpretation mode. All macros expand normally and type hints are processed they just
don’t do anything.&lt;/p&gt;

&lt;p&gt;Once the whole namespace has been successfully loaded in interpretation mode, a second pass may be
made in which static linking is performed. Because everything in the namespace has been fully
realized already it’s possible to statically link even mutually recursive calls within the same
namespace. Full type inference within the namespace is also possible here, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aside&lt;/strong&gt;: Interestingly because it is single pass, the existing Clojure compiler doesn’t (can’t)
handle hinted mutually recursive function calls at all. It relies on Var metadata to store arglists
(and hints for primitive invocations), so in order to emit a hinted recursive call the forward
declaration of the var has to carry the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^:arglists&lt;/code&gt; metadata (hints and all!) which will be
added by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;defn&lt;/code&gt; whenever it is finally defined.&lt;/p&gt;

&lt;p&gt;Once a namespace has been fully loaded and compiled (including the second pass) the global
environment with the resulting namespace and var mappings is the result of whatever caused
loading. If an error occurs during compilation, we just abort and return the environment state
before anything else happened. I think there are tricks to be played with generated garbage class
names and classloader isolation here so that this works even during the 2nd static compile pass, but
it should be possible to fully clean up a failed compile.&lt;/p&gt;

&lt;p&gt;So this works really great for module loading, and even for macros which expand into multiple def
forms. This model of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval :: env -&amp;gt; form -&amp;gt; (env, result)&lt;/code&gt; starts to break down when you want to
talk about macros that do evaluation during code loading, and likewise the REPL. Basically your
interpreter winds up holding an additional reference, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*env*&lt;/code&gt; or something, which is intrinsically
mutable, but which references an immutable environment and holds shall we say the state continuation
of the entire REPL. Consider user code which actually calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval&lt;/code&gt; during execution. Whatever state
changes that evaluation creates need to be preserved in the “global” continuation.&lt;/p&gt;

&lt;p&gt;In this model when you compile a form at the REPL, the runtime could obviously interpret (this may
be appropriate for macroexpansion) and can also compile. This is only tricky when the user
recompiles a symbol which was already bound/compiled. In this case, the runtime could either eagerly
recompile all the code which links against this function using the same interpret then statically
link tactic or could just invalidate any compiled bytecodes and lazily recompile later. The former
is probably more predictable.&lt;/p&gt;

&lt;p&gt;Once a namespace has been reloaded/altered, all namespaces importing it must also be recompiled in
topsort order using the same tactics. That we already have per-symbol dependency information and
per-module dependency information helps with building refactoring tools which otherwise have to
derive all this themselves. Ideally top level expressions/definitions would also expose local
variable tables tables and local variable dataflow graphs so that analysis there is also possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aside&lt;/strong&gt;: It may be possible to allow cyclic dependencies between namespaces (see
&lt;a href=&quot;https://www.cs.utah.edu/plt/publications/gpce13-f-color.pdf&quot;&gt;submodules in racket&lt;/a&gt; for some study
on this problem). In the common case it may well be that macros are well behaved and that cyclic
dependencies between modules work out just fine. However because macros perform arbitrary
computation it’s also pretty easy to cook up pathological cases where macro generated code never
reaches a fixed point in repeated interpretive analysis which can be statically compiled. For this
reason I’m inclined towards formalizing a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ns&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;module&lt;/code&gt; special form and throwing out &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require&lt;/code&gt;,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;refer&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import&lt;/code&gt; and friends as legal top level forms altogether. Namespaces should be declarative
as in Java/Haskell.&lt;/p&gt;

&lt;p&gt;There’s probably a way which I just haven’t seen yet to treat updates to the “global” namespace
mapping and updates within a namespace the same way via the same mechanism since they’re both
dependent on the same dependency tracking and recompile machinery.&lt;/p&gt;

&lt;p&gt;Writing this has made me think about having an ImmutableClassLoader which is derived entirely from a
immutable environment and loads classes by lazily (statically) compiling forms.&lt;/p&gt;

&lt;p&gt;That’s kinda all I got. ztellman gets credit for the mutable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*env*&lt;/code&gt; in the repl bit which I spent
literally weeks trying to do without last year. Maybe something with monad transformers can get you
there but I couldn’t figure it out. mikera has some sketches of all this with types in his
&lt;a href=&quot;https://github.com/mikera/kiss/&quot;&gt;KISS&lt;/a&gt; project.&lt;/p&gt;

&lt;p&gt;I’ve already prototyped an environment system that looks a lot like this in the Ox repo if you want
to go dig. Originally there was this
&lt;a href=&quot;https://github.com/ox-lang/ox/blob/develop/src/main/clj/ox/lang/environment.clj&quot;&gt;ox/lang/environment.clj&lt;/a&gt;
then I started dinking with a Java implementation of the environment structure
&lt;a href=&quot;https://github.com/ox-lang/ox/tree/develop/src/main/java/ox/lang/environment&quot;&gt;ox/lang/environment&lt;/a&gt;
which also has a couple different stack based contextual binding types for the interpreter.&lt;/p&gt;

&lt;p&gt;As written about in the Jaunt essays, I’ve kinda concluded that whatever this immutable ns language
winds up looking like is so divorced from what Clojure or at least the way that most people write
Clojure that you’ll loose so much value in the changeover it won’t pay off for a very long time. The
&lt;a href=&quot;https://github.com/tolitius/mount&quot;&gt;mount&lt;/a&gt; library is a perfect example of this in that it’s deeply
imperative and takes advantage of code loading order to achieve start and stop. It’s not the only
bit of code I’ve seen which does effects at load time either. Hence Jaunt which tries to be less
flawed around namespace reloading/refactoring without going whole hog on ns immutability.&lt;/p&gt;

&lt;p&gt;The more I kick this stuff around the more I find that the whole endeavor verges on a Haskell clone
in sexprs and the more I decide I’d rather take the time to learn Haskell properly than mess with an
immutable lisp or Jaunt. Besides then you get nice stuff like typeclasses and fully typed instance
dispatch and equality that actually works and theorems and native bytecode and yeah.&lt;/p&gt;

&lt;p&gt;^d&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Deprecation warnings in Jaunt</title>
    <link href="https://www.arrdem.com/2016/03/08/jaunt_deprecation/"/>
    <updated>2016-03-08T06:56:12+00:00</updated>
    <id>https://www.arrdem.com/2016/03/08/jaunt_deprecation</id>
    <content type="html">&lt;p&gt;This week I’m working on getting &lt;a href=&quot;https://github.com/jaunt-lang/jaunt&quot;&gt;Jaunt&lt;/a&gt;’s 1.9.0 release nearer
the door, on which note I’m happy to properly demo one the features of this first release:
deprecation warnings.&lt;/p&gt;

&lt;p&gt;A bare REPL will do for these demos.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cd $(mktemp -d)
$ wget https://clojars.org/repo/org/jaunt-lang/jaunt/1.9.0-RC4/jaunt-1.9.0-RC4.jar
$ java -jar jaunt-1.9-RC4.jar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/jaunt-lang/jaunt/pull/2&quot;&gt;Jaunt #2&lt;/a&gt; (not my best ticket ever in terms of hygiene)
was the first work I did on what became Jaunt and was really pretty critical for getting my teeth
into the project and validating that there were tractable incremental improvements to be made over
Clojure.&lt;/p&gt;

&lt;p&gt;This change introduced four new switches to the Jaunt compiler, the most interesting of which is
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:warn-on-deprecated&lt;/code&gt; which enables or disables compiler warnings in support the use of
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^:deprecated&lt;/code&gt; metadata on functions and namespaces. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:warn-on-deprecated&lt;/code&gt; is on (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;) by
default, although it can be disabled globally with the JVM system property
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.compiler.warn-on-deprecated=false&lt;/code&gt;, or by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set!&lt;/code&gt;ing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.core/*compiler-options*&lt;/code&gt; say
to have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(set! *compiler-options* (dissoc *compiler-options* :warn-on-deprecated))&lt;/code&gt; in a namespace
where you want these checks to be disabled.&lt;/p&gt;

&lt;p&gt;The semantics of deprecation are simple:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A namespace is deprecated if and only if it has the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^:deprecated&lt;/code&gt; metadata.&lt;/li&gt;
  &lt;li&gt;A definition (Var) is deprecated if either it occurs within a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^:deprecated&lt;/code&gt; namespace, or is
itself marked &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^:deprecated&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vars and namespaces may become deprecated in any SemVer minor version or major version, but may only
legally be deleted only on a major version.&lt;/p&gt;

&lt;p&gt;Deprecation warnings are only emitted when a deprecated namespace or definition is accessed from a
context which is not deprecated. Deprecated contexts are namespaces which are deprecated, and the
bodies of deprecated definitions.&lt;/p&gt;

&lt;p&gt;So for instance, in the following code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:deprecated&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bad-idea&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Oh noez!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Exception&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Bad code is bad&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; #&apos;user/bad-idea&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:deprecated&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;also-bad-idea&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;bad-idea&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; #&apos;user/also-bad-idea&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;almost-better-idea&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;bad-idea&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; Warning: using deprecated var: #&apos;user/bad-idea ...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; #&apos;user/also-bad-idea&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The definition of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bad-idea&lt;/code&gt; itself is innocuous. Simply evaluating deprecated definitions is
fine. Warning that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;also-bad-idea&lt;/code&gt; uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bad-idea&lt;/code&gt; would be superfluous, because that fact is
innocuous so long as neither is used. Suppressing warnings in this case allows Jaunt to load
arbitrarily much deprecated code without drowning a user with false positive warnings.&lt;/p&gt;

&lt;p&gt;Users should only have to care about deprecation at the edge between current code and deprecated
code. Thus compiling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;almost-better-idea&lt;/code&gt; will emit a warning that it makes use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bad-idea&lt;/code&gt;, since
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;almost-better-idea&lt;/code&gt; is not itself deprecated. Likewise at the repl invoking either deprecated
function would also generate a warning.&lt;/p&gt;

&lt;p&gt;As to namespaces, similar principles apply. Consider the two namespaces and trace:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:deprecated&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;com.proj.code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; nil&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;some-const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; #&apos;com.proj.code/some-const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;;------------------------------------------------------------------------&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;com.proj.new-code&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:require&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;com.proj.code&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:as&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;old&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:refer&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;some-const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; Warning: aliasing deprecated ns: com.proj.code  ...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; Warning: referring deprecated var: #&apos;com.proj.code/some-const ...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; nil&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; #&apos;com.proj.new-code/g&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;old/some-const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; Warning: using deprecated var: #&apos;com.proj.code/some-const ...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; #&apos;com.proj.new-code/h&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As the whole &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.proj.code&lt;/code&gt; namespace is deprecated, merely referencing it and requiring that it be
loaded is cause for a warning. Should that namespace ever be removed, the require would break
regardless of whether anything from the required namespace is used or not.&lt;/p&gt;

&lt;p&gt;If symbols which are deprecated are referred into a namespace which is not deprecated, each one of
those will generate a warning as well for the same reason. However Jaunt tries to be smart about
this, suppressing such warnings if a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(require &apos; [... :refer :all])&lt;/code&gt; or a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(use ...)&lt;/code&gt; directive has
been issued which constitutes an indefinite referral.&lt;/p&gt;

&lt;p&gt;The symbol &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.proj.code/some-const&lt;/code&gt;, is deprecated by dint of being defined in a deprecated
namespace. Consequently a warning is emitted when it is used outside of a deprecated context, here
in the definition of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;com.proj.new-code/h&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One last demo, disabling warnings!&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;com.proj.no-warnings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; nil&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set!&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;*compiler-options*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; 
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;dissoc&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;*compiler-options*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:warn-on-deprecated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; elided...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:deprecated&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; #&apos;com.proj.no-warnings/a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; #&apos;com.proj.no-warnings/b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There’s more than just this coming down the line in Jaunt, so if you’re interested check out the
&lt;a href=&quot;https://github.com/jaunt-lang/jaunt/blob/release/1.9.0/CHANGELOG.md&quot;&gt;1.9 CHANGELOG&lt;/a&gt;, watch
&lt;a href=&quot;https://github.com/jaunt-lang/jaunt&quot;&gt;the repo&lt;/a&gt; or stay tuned here for more demos. Issues, ideas and
especially pull requests are welcome &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:D&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;^d&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Jaunt - A friendly Clojure fork</title>
    <link href="https://www.arrdem.com/2016/02/22/clojarr_-_a_friendly_clojure_fork/"/>
    <updated>2016-02-22T13:00:00+00:00</updated>
    <id>https://www.arrdem.com/2016/02/22/clojarr_-_a_friendly_clojure_fork</id>
    <content type="html">&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;

&lt;p&gt;I’ve started a fork of Clojure which I intend to operate in a
community directed manner;
&lt;a href=&quot;https://github.com/jaunt-lang/jaunt&quot;&gt;Jaunt&lt;/a&gt;. Check out the
&lt;a href=&quot;#demo&quot;&gt;demo script&lt;/a&gt; or just keep reading for
more.&lt;/p&gt;

&lt;h2 id=&quot;the-long-version&quot;&gt;The Long Version&lt;/h2&gt;

&lt;p&gt;After several months of dinking with
&lt;a href=&quot;/tags/#Oxlang-ref&quot;&gt;Oxlang&lt;/a&gt; on and off I came to a
realization.  Ox, while an annoyingly persistent daydream was doomed
to be one of two things.  Either it would be something akin to Haskell
in S expressions, or it would be indistinguishable from Clojure with
some tweaks under the hood.&lt;/p&gt;

&lt;p&gt;I’d gotten Ox’s reader sort of working, and was starting to experiment
with notations, explore notions of higher kinded types and generally
was having a ball.  However even getting that far was a highly
educational exercise in how much Clojure already does fairly well. To
continue down the road of Ox was to admit that I’d have to reinvent
all of Clojure’s datastructures, most of the Clojure compiler and a
whole boatload of the standard library. It was also to admit that due
to limitations of the JVM as a target, I wouldn’t be able to play some
of the many tricks which the GHC folks get to play even were I to go
down the road of a pure language.&lt;/p&gt;

&lt;p&gt;Why do all this? Because it’s hard? I’m no Heracles seeking labors
&lt;a href=&quot;http://metayaks.com/&quot;&gt;or yaks&lt;/a&gt; for their own sake. I’d rather be
learning something new or playing Dota or… a thousand other things.&lt;/p&gt;

&lt;center&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;YOUR FINEST YAK SIR&lt;/p&gt;&amp;mdash; tail -f /dev/ardm0 (@arrdem) &lt;a href=&quot;https://twitter.com/arrdem/status/698341845957382146&quot;&gt;February 13, 2016&lt;/a&gt;&lt;/blockquote&gt;&lt;/center&gt;

&lt;p&gt;I swear I would.&lt;/p&gt;

&lt;p&gt;Besides, even though &lt;a href=&quot;https://twitter.com/mtrimpe&quot;&gt;Michiel Trimpe&lt;/a&gt; was
kind enough
&lt;a href=&quot;https://skillsmatter.com/skillscasts/7277-conversational-computing-how-okasaki-made-mccarthy-right-yet-again&quot;&gt;to mention Ox&lt;/a&gt;
alongside a number of other “conversational” programming languages in
his ClojureX talk, I’m not convinced that it’s a good idea.&lt;/p&gt;

&lt;p&gt;In looking back at that particular talk, one thing struck me. Sure in
a pure functional programming language such as Haskell you could stick
an arbitrary AST in a Merkle tree and have a globally distributed
version control and distribution system with strong guarantees about
tree uniqueness and reuse safety.&lt;/p&gt;

&lt;p&gt;Unfortunately, Clojure is no such beast. We have no language level
concept of effects (okay we have the
&lt;a href=&quot;http://conj.io/store/v1/org.clojure/clojure/1.7.0/clj/clojure.core/io%21/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;io!&lt;/code&gt;&lt;/a&gt;
macro but that’s hardly the same). While you could implement immutable
namespaces (and in fact they are backed by immutable maps already) the
concept doesn’t make a whole lot of sense to me.&lt;/p&gt;

&lt;p&gt;The very notion of a conversational language is that you can reference
any definition from any version of the program as if it were the
current version. What does this look like at a REPL? Are namespaces
(or rather full states) identified with a commit ID and compilation
occurs in terms of a fully qualified “commit” and Var? Now we need
notation for that. Maybe version/name/namespace or something. Some
sort of explorer to browse older commits is in order… the list goes
on and on. In short, I think you wind up reinventing a bunch of stuff
that git already does pretty well.&lt;/p&gt;

&lt;p&gt;This is not to say that Clojure’s existing mutable namespaces are
ideal. For me, they work against the ns or file level code loading
style I use when developing Clojure code. Old habits from C die hard
as it were. A common failure mode I encounter is that I’ll rename a
function but not all of its uses. IntelliJ and refactor-nrepl can be
of some help here, but I’ve had them break down and I’m not always in
a “full ide” configuration. Because namespaces are mutable, even if I
were to perform a rename correctly, the old name is still present in
the namespace. If I got it wrong, my code reloads, all symbols
resolved then I get Really Cool Unexpected Behavior when parts of my
code call the new function and parts call the old function. Or worse
my code works fine until I restart my repl or the test server and
everything explodes. Or the old name just sticks around cluttering up
my autocompletion.&lt;/p&gt;

&lt;p&gt;This becomes a real UX problem for me, because I rely heavily on
refactoring. I start by sketching out what amount to types, or
deriving operations from types I already have, and keep working
renaming and moving code around until I get something I’m happy with.&lt;/p&gt;

&lt;center&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://twitter.com/arrdem&quot;&gt;@arrdem&lt;/a&gt; your problem is all the refactoring. Why isn&amp;#39;t the code right from the start?&lt;/p&gt;&amp;mdash; Chas Emerick (@cemerick) &lt;a href=&quot;https://twitter.com/cemerick/status/679482166426910721&quot;&gt;December 23, 2015&lt;/a&gt;&lt;/blockquote&gt;&lt;/center&gt;

&lt;h2 id=&quot;and-yet-i-shave&quot;&gt;And Yet I Shave&lt;/h2&gt;

&lt;p&gt;The thing which came to me now a few weeks ago is that there’s an
interesting halfway house between these two extremes of mutable and
immutable namespaces. What if we gave Namespaces and Vars version
numbers? When a Namespace is re-defined (the ns form is evaluated)
then the Namespace’s version is incremented. When a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;def&lt;/code&gt; is evaluated,
the version of the Var bound by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;def&lt;/code&gt; is set to be the version of
the Namespace in which that Var exists.&lt;/p&gt;

&lt;p&gt;This allows traditional REPL style interaction with Namespaces. You
may enter a Namespace, add bindings, aliases, imports and so forth as
you will. However the version numbers give you important static
information about the state of the Var in its Namespace.&lt;/p&gt;

&lt;p&gt;If I have some &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;def&lt;/code&gt; which I entered at the REPL, when I do something
to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ns&lt;/code&gt; backing file and reload it, that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;def&lt;/code&gt; persists. But, its
version is now out of sync with the Namespace it exists within. When
we reloaded the file, the Namespace’s version was incremented and then
every definition was reevaluated. If my code is still using an old
symbol which is not textually present in the file and was was not
reloaded, its version doesn’t increase.  Now the compiler can detect
the version disparity and emit warnings that I’m using old code.&lt;/p&gt;

&lt;p&gt;While this solves dependency freshness issues within a single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;def&lt;/code&gt;
and a single Namespace, solving them globally requires more leg
work. The compiler needs to be adapted to track the use and reach sets
of each compiled expression, and to inter that information into the
Var binding forms so that it’s possible for a newly compiled form to
emit warnings about transitive use of stale vars.&lt;/p&gt;

&lt;p&gt;These changes don’t alter the semantics of the Namespace at all
outside of reloading. If you evaluate a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;def&lt;/code&gt; or a single form in
a Namespace it works just as before. However if you take this whole
file reloading approach, the language can offer added support which
papers over a rather painful pitfall.&lt;/p&gt;

&lt;p&gt;A related change is that Namespaces can be made to purge their imports
and aliases on reload. Right now, Namespaces persist imports and
aliases until the VM is restarted. This leads to a nasty set of
refactoring problems where you want to change the name of an alias,
but can’t reuse a name because aliases are never cleared. If we
consider a whole Namespace and its source file(s) as the unit of
compilation we can again do better. This is another language level
change which would meaningfully improve my day to day use of the
language without breaking existing use patterns.&lt;/p&gt;

&lt;p&gt;Both of these changes turn out to be quite simple to implement. In the
course of only a few days I went from the concept of these changes to
a build of Clojure (&lt;a href=&quot;https://github.com/jaunt-lang/jaunt/clojarr/pull/60&quot;&gt;pr&lt;/a&gt;,
&lt;a href=&quot;https://clojars.org/me.arrdem/clojarr/versions/1.9.0-e3f38f1-SNAPSHOT&quot;&gt;build&lt;/a&gt;)
which features Namespace clearing and Var versions. I’m using now
daily because it better supports the way that I want to work with the
language.&lt;/p&gt;

&lt;h2 id=&quot;waxing-political&quot;&gt;Waxing Political&lt;/h2&gt;

&lt;p&gt;Rich, Stuart Sierra, Stu Halloway, Alex and the rest of the
Clojure/Core crew (see
&lt;a href=&quot;http://clojure.com/blog/2012/02/17/clojure-governance.html&quot;&gt;Clojure/Huh?&lt;/a&gt;)
built Clojure and have shepherded it this far. I’m immensely grateful
to them for the work they’ve done to date in building a tool which
I’ve had great fun using. But I think our priorities diverge.&lt;/p&gt;

&lt;p&gt;From what I’ve been able to gather by talking to people who’ve been
around longer and
&lt;a href=&quot;https://web.archive.org/web/20150520102255/http://clojure.org/funding&quot;&gt;what Rich has written&lt;/a&gt;,
it should be clear that Clojure is not a community project in the same
way Python or Rust is. Clojure is Rich’s personal project, which he is
so kind as to share with the rest of us and in in its refinement Rich
chooses to accept some amount of input from us as users. I’m somewhat
ashamed to admit that it took me two years to realize this.&lt;/p&gt;

&lt;center&gt;&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Open-source development problem in one sentence: &lt;br /&gt;&amp;quot;Users assume they are customers&amp;quot;&lt;/p&gt;&amp;mdash; Aleksey Shipilëv (@shipilev) &lt;a href=&quot;https://twitter.com/shipilev/status/689893251625684995&quot;&gt;January 20, 2016&lt;/a&gt;&lt;/blockquote&gt;&lt;/center&gt;

&lt;p&gt;Discussion of particulars, and the reasons for the status quo is I
think a somewhat useless exercise. Rich has his project and
administers it as he sees fit. As Clojure is Rich’s project, the
priority of its governance is to conserve Rich’s time and it has
repeatedly been made clear that there is no desire to change
this. This is an eminently reasonable goal I can find no fault
in. Rich doesn’t owe me or anyone else jack, let alone time. However
the consequence of this structure and of not delegating is the slow
and steady path which frustrates my desires for more rapid iteration.&lt;/p&gt;

&lt;h2 id=&quot;a-fork-in-the-road&quot;&gt;A Fork in the Road&lt;/h2&gt;

&lt;p&gt;With loyalty the path of the last 18 months and clearly one of
frustration, and voice ineffective due to the (reasonable!) priorities
of Clojure/Core, The only course of action left to me is some form
of
&lt;a href=&quot;https://www.goodreads.com/book/show/149033.Exit_Voice_and_Loyalty&quot;&gt;exit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I think that there’s a lot of possible improvements that can still be
made to the language. Currently there doesn’t seem to be a lot of
appetite for exploring that in Clojure itself. The namespace reloading
stuff sketched above is just the first thing that popped to mind when
I started thinking about how to improve my day to day experience and
implementing that alone has shaken loose a number of other small but
worthy improvements.&lt;/p&gt;

&lt;p&gt;The consequence of this opinion is that I’ve started
&lt;a href=&quot;https://github.com/jaunt-lang/jaunt&quot;&gt;Jaunt&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Jaunt is my personal fork of Clojure which seeks to deal with the
various organizational and technical limitations expressed above.&lt;/p&gt;

&lt;p&gt;Technically, with Jaunt I want to explore a space of refinements to
the language such as the Namespace reloading changes sketched above
which add value without breaking compatibility with the ecosystem of
libraries and tools like CIDER which I’ve come to rely on every day.&lt;/p&gt;

&lt;p&gt;Organizationally, I want Jaunt to be a community driven affair. I
don’t claim that my judgment is infallible, nor do I think I’ll have
all the good ideas, nor will I have infinite time to consider changes
even were these restrictions lifted. I’d love to involve contributors
who want to bring improvements to the project within the stated bounds
of preserving compatibility at least with the documented parts of
Clojure.&lt;/p&gt;

&lt;h2 id=&quot;demo&quot;&gt;Demo&lt;/h2&gt;

&lt;p&gt;Because otherwise how do you believe that any of this works, here’s a
script that’ll build a empty
&lt;a href=&quot;https://github.com/technomancy/leiningen&quot;&gt;leiningen&lt;/a&gt; project in a
temporary directory and run a quick demo of some of the stale Var
stuff.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/arrdem/3e4fe82a583368dc9d83.js&quot;&gt;&lt;/script&gt;

&lt;h2 id=&quot;no-promises&quot;&gt;No Promises&lt;/h2&gt;

&lt;p&gt;If you want a stable language. If you’re running code in
production. If you don’t want to get down and dirty with the language
implementation or the development process, stick with Clojure.&lt;/p&gt;

&lt;p&gt;As the EPL states:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
LIMITATION, ANY WARRANTIES OR CONDITIONS OF … FITNESS FOR A
PARTICULAR PURPOSE.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Jaunt should be a drop in replacement for Clojure. I want to keep it
compatible. I foresee no reason to break the documented Clojure
API. But some amount of drift is inevitable. I’ve already moved some
stuff around inside the Java implementation. If you were depending on
those undocumented yet public implementation details, all bets are
off. I’ve
&lt;a href=&quot;https://github.com/arrdem/clojarr/pull/62&quot;&gt;changed how metadata behaves on vars&lt;/a&gt;
(I think it’s a better approach but it does impose behavioral
differences). I’ve
&lt;a href=&quot;https://github.com/arrdem/clojarr/pull/2&quot;&gt;added deprecated warnings&lt;/a&gt;. I
added &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.core/*line*&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.core/*column*&lt;/code&gt;
(&lt;a href=&quot;https://github.com/arrdem/clojarr/pull/52&quot;&gt;pr&lt;/a&gt;) which the compiler
totally had internally and just didn’t expose
&lt;a href=&quot;https://github.com/arrdem/clojarr/commit/367a2fa0b36990b9c6aa90bfaf1810e310f59091&quot;&gt;forcing weirdness&lt;/a&gt;. And
this list of differences (perhaps improvements) is just going to grow.&lt;/p&gt;

&lt;p&gt;Whether Jaunt proves to be something I depend on in the future,
whether I wander off into the land of types and leave it to someone
else or whether it diverges too much from Clojure and dies as a result
of the weight of its mutations, I’ve overheard enough interest in a
project such as this that I think this is a worthwhile endeavor and I
hope you’ll join me in this little adventure.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update:&lt;/em&gt; Clojarr has been renamed to Jaunt, updated article accordingly.&lt;/p&gt;

&lt;p&gt;^d&lt;/p&gt;

&lt;script async=&quot;&quot; src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

</content>
  </entry>
  
  <entry>
    <title>Hacking like it's 2288</title>
    <link href="https://www.arrdem.com/2015/11/17/hacking_like_it's_2288/"/>
    <updated>2015-11-17T08:22:39+00:00</updated>
    <id>https://www.arrdem.com/2015/11/17/hacking_like_it's_2288</id>
    <content type="html">&lt;p&gt;I’m an a diehard Fallout franchise fan.  While school currently
precludes me from playing, I took some time to automate solving the
hacking minigame which is used to unlock computer terminals and
secured areas in-game.&lt;/p&gt;

&lt;center&gt;
  &lt;img src=&quot;http://images.akamai.steamusercontent.com/ugc/25091655368806142/5B46AF039157704AF07C96155AA45B04BAFAA045/&quot; /&gt;
&lt;/center&gt;

&lt;p&gt;When “hacking”, a player is presented with a list of words one of
which is the “password” and has five (or fewer) tries to try and find
the password. Every time the user selects a candidate, a response of
how many characters match between the answer and the candidate is
given so that the user can refine their guess.&lt;/p&gt;

&lt;p&gt;The strategy for playing this game is uninteresting at best, you
choose an initial word either heuristically or randomly, and then
based on the number of characters which that word shares with the
answer you can refine the whole list of words by removing all words
which do not share exactly that many characters with the word you
tried. This simple guess and refine algorithm one need only iterate
until only one answer remains.&lt;/p&gt;

&lt;p&gt;While an obvious algorithm, it’s a little tedious to do this by hand
because there’s no good way to keep track of all the candidates which
have been removed from consideration. Also computing string overlaps
is boring. Given an algorithmic problem, write an algorithmic
solition! What do we need to solve this problem in Clojure?&lt;/p&gt;

&lt;p&gt;Well first we need our word “intersection” scoring function. To do
this, we’ll take the frequencies of the left word, the frequencies of
the right word. Since each character can only correspond to another
single character, this means that given N as on the laft and M bs on
the right, we have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(min N M)&lt;/code&gt; common characters. We can simply
compute this common character count for every character in the left
string (characters occuring only in the right string won’t factor in
anyway) and take the sum over those counts.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;letters-in-common&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;frequencies&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fr&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;frequencies&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
               &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vr&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fr&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vl&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
         &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;letters-in-common&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;foooo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; 3&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;letters-in-common&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cat&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;dog&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; 0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;letters-in-common&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cat&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;rat&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; 2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So now we need a guess making function which we can write in terms of
our scoring function. What word do we want to choose as our guess?
Well we want to guess the word which will give us the most information
about all the other words, that is to say is most similar to as many
other words as possible.&lt;/p&gt;

&lt;p&gt;Once we’ve made a guess we can use the word similarity score we get
back to refine our dictionary and contrain our search space.&lt;/p&gt;

&lt;p&gt;This must be the optimal choice by the usual greedy choice argument,
since any other word we could guess would tell us less about the other
words, and in the case of a tie (two words with equal similarity to
all other words) we can’t know without guessing which one is the
better choice so we can choose randomly.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make-guess&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Given a population of words, locates and returns a word with maximum
  \&quot;matching potential\&quot;, that is the word which shares the most
  characters with every other word.

  If there is a tie, since the two words have equal potentials it
  doesn&apos;t matter which one we choose and so the choice is arbitrary.

  Makes use of scoped memoization for performance on lots of words,
  but realistically this should never be a factor.&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;-score-fn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;memoize&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                     &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                       &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;letters-in-common&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score-fn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sorted-set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                                 &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:when&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;not=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-score-fn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;conj&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                           &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sort-by&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score-fn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now we need our dictionary pruning function.  If a word does not have
exactly n letters in common with the last guess where n is the
reported similarity of the last guess with the answer, that word
cannot be a solution.&lt;/p&gt;

&lt;p&gt;We know that for multiple guesses, no word could be an answer which
does not have the reported similarity with all previous guesses. Thus
we don’t accidentially exclude any possible answers by simply
filtering the dictionary as such after each guess.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;trim-pop&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;guess&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;commonality&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;     &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:when&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;commonality&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;letters-in-common&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;guess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;trim-pop&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cat&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;rat&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;cat&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; =&amp;gt; (&quot;rat&quot;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So lets put these two to use! We’ll wire up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make-guess&lt;/code&gt; to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;letters-in-common&lt;/code&gt; which is our scoring function anyway and just let
it run on a small dictionary and a goal word. Just to make the point
that this algorithm does converge.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;c1&quot;&gt;;; An example hacking loop. The guess and refine algorithm with a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; sample input.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;LOWER&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;CREED&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;JAMES&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;CAGES&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;CARES&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;OFFER&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;CAVES&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;TIRED&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;answer&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;LOWER&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;loop&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;guess&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;make-guess&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;letters-in-common&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;guess&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;answer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;trim-pop&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;guess&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Guessed&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;guess&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;reduced population to&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;recur&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Yay! So that totally works.&lt;/p&gt;

&lt;p&gt;And because I don’t think anyone wants to manually run all that state
through a REPL while trying to play Fallout 4, here’s a quick REPL
wrapper to help with hacking.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;autohack&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;if-not&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;guess&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;make-guess&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;     &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Try&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;guess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;recur&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;trim-pop&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;guess&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;It&apos;s&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Happy wandering!&lt;/p&gt;

&lt;p&gt;^d&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Strictly Tagged Clojure</title>
    <link href="https://www.arrdem.com/2015/08/03/Strictly-Tagged-Clojure-Core/"/>
    <updated>2015-08-03T19:00:00+00:00</updated>
    <id>https://www.arrdem.com/2015/08/03/Strictly-Tagged-Clojure-Core</id>
    <content type="html">&lt;p&gt;This summer I’ve been an intern at &lt;a href=&quot;http://factual.com&quot;&gt;Factual&lt;/a&gt;, and this is an
experience report from the semiannual internal hackathon where
&lt;a href=&quot;https://github.com/amalloy&quot;&gt;Alan ‘amalloy’ Malloy&lt;/a&gt; and I experimented with
using &lt;a href=&quot;http://www.bytopia.org/&quot;&gt;Alexander Yakushev&lt;/a&gt;’s
&lt;a href=&quot;http://clojure-android.info/skummet/&quot;&gt;Skummet&lt;/a&gt; fork of Clojure to emit lean(er)
bytecode.&lt;/p&gt;

&lt;h2 id=&quot;some-motivation&quot;&gt;Some motivation&lt;/h2&gt;

&lt;p&gt;One of Clojure’s primary use cases is as a more palatable tool with which to
interact with the rich Java ecosystem and existing Java libraries. Because of
its facilities for such inter-operation, Clojure is even sometimes used to write
performance sensitive code which would otherwise be written in Java. However
there are limitations to the success with which this may be done.&lt;/p&gt;

&lt;p&gt;While JVM bytecode is statically typed, Clojure is an aggressively
dynamically checked language which makes pervasive use of the Object
type to delay typechecking. To this end, Clojure will use JVM Object
reflection to resolve instance fields and methods when performing
interoperation. While correct for unknown types, because reflective
access is slow compared to direct access for known types it has long
been possible to write
&lt;a href=&quot;http://clojure.org/java_interop#Java%20Interop-Type%20Hints&quot;&gt;type hints&lt;/a&gt;
which advise Clojure about the runtime JVM type of a value and enable
Clojure to use direct access and direct method invocation rather than
reflective access.&lt;/p&gt;

&lt;p&gt;However these hints are &lt;em&gt;not&lt;/em&gt; types in the sense of a static type being a
contract on the domain of values, they are merely hints for reflection
elimination and place no contract on the domain of a hinted value.&lt;/p&gt;

&lt;p&gt;This hinting behavior for reflection elimination comes at the cost of emitting
&lt;a href=&quot;http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.checkcast&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkcast&lt;/code&gt;&lt;/a&gt;
instructions. As the JVM is statically typed, one cannot simply swear that a
value is of a type, a checking cast must be used. Clojure, when emitting
non-reflective method calls and field accesses, does not statically know (and
makes no attempt to prove) that the value or expression in play is in fact of
the type which you may have tagged it. All local variables and function
parameters which are not JVM primitives are stored as Objects and so must be
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkcast&lt;/code&gt;ed to the desired type on every use.&lt;/p&gt;

&lt;p&gt;So are we stuck trading slow reflective access for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkcast&lt;/code&gt; instructions
(which are faster to be sure but cause method bloat when doing lots of interop
on previously checked values)?&lt;/p&gt;

&lt;p&gt;Of course not! While Clojure does not currently have support for real
contractual types when using tags, we can sure add such behavior!&lt;/p&gt;

&lt;p&gt;Now. Before you burn me at the stake for being a heretic, clearly since Clojure
does not currently have strict local types, we can’t just make tags strict.
&lt;a href=&quot;https://github.com/clojure/tools.emitter.jvm&quot;&gt;TEMJVM&lt;/a&gt; actually
&lt;a href=&quot;http://dev.clojure.org/jira/browse/TEMJVM-14&quot;&gt;makes that mistake&lt;/a&gt;, and as a
result cannot compile &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure/core&lt;/code&gt; because among others,
&lt;a href=&quot;https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L4038-L4047&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.core/ns-publics&lt;/code&gt;&lt;/a&gt;
makes use of a type hint which while safe for nonstrict type tags is not correct
in the context of strict tags. This has to be an additive, opt-in change.&lt;/p&gt;

&lt;p&gt;So, what Alan and I did was create new special &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fn&lt;/code&gt; metadata flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^:strict&lt;/code&gt;. If
a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fn&lt;/code&gt; body being compiled has the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^:strict&lt;/code&gt; tag, then and only then are are
type tags treated as a contract rather than being advisory. This is a strictly
additive change because stock Clojure will ignore the metadata and emit less
efficient but still correct code.&lt;/p&gt;

&lt;p&gt;So as an example, let’s consider the following fn:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Iterable&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.iterator&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;loop&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tot&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.hasNext&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;recur&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tot&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.next&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Eliding a bunch of implementation details for brevity, this fn compiles
&lt;strong&gt;on stock Clojure 1.7&lt;/strong&gt; to the following JVM bytecodes:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public final long invokePrim(java.lang.Object xs);
   0  aload_1 [xs]
   1  aconst_null
   2  astore_1 [xs]
   3  checkcast java.lang.Iterable [47]
   6  invokeinterface java.lang.Iterable.iterator() : java.util.Iterator [51] [nargs: 1]
  11  astore_2 [iter]
  12  lconst_0
  13  nop
  14  lstore_3 [tot]
  15  aload_2 [iter]
  16  checkcast java.util.Iterator [53]
  19  invokeinterface java.util.Iterator.hasNext() : boolean [57] [nargs: 1]
  24  ifeq 51
  27  lload_3 [tot]
  28  aload_2 [iter]
  29  checkcast java.util.Iterator [53]
  32  invokeinterface java.util.Iterator.next() : java.lang.Object [61] [nargs: 1]
  37  invokestatic clojure.lang.RT.longCast(java.lang.Object) : long [64]
  40  invokestatic clojure.lang.Numbers.add(long, long) : long [70]
  43  lstore_3 [tot]
  44  goto 15
  47  goto 52
  50  pop
  51  lload_3
  52  lreturn
    Local variable table:
      [pc: 15, pc: 52] local: tot index: 3 type: long
      [pc: 12, pc: 52] local: iter index: 2 type: java.lang.Object
      [pc: 0, pc: 52] local: this index: 0 type: java.lang.Object
      [pc: 0, pc: 52] local: xs index: 1 type: java.lang.Object

// Method descriptor #77 (Ljava/lang/Object;)Ljava/lang/Object;
// Stack: 5, Locals: 2
public java.lang.Object invoke(java.lang.Object arg0);
   0  aload_0 [this]
   1  aload_1 [arg0]
   2  invokeinterface clojure.lang.IFn$OL.invokePrim(java.lang.Object) : long [79] [nargs: 2]
   7  new java.lang.Long [30]
  10  dup_x2
  11  dup_x2
  12  pop
  13  invokespecial java.lang.Long(long) [82]
  16  areturn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So here we have two methods. The first one, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invokePrim&lt;/code&gt;, takes an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt;
and returns a primitive &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;long&lt;/code&gt; since we long hinted our function. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invoke&lt;/code&gt;
method is a wrapper around the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invokePrim&lt;/code&gt; method which provides for “boxing”
(wrapping in an object) the primitive result of calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invokePrim&lt;/code&gt;. This
allows our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fn&lt;/code&gt; to be used by code which wants and can use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;long&lt;/code&gt;, and code
which doesn’t know/care and just wants an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt; back like a normal &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fn&lt;/code&gt; would
return.&lt;/p&gt;

&lt;p&gt;So lets dig into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invokePrim&lt;/code&gt; method.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Load &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xs&lt;/code&gt; off the arguments stack. It’s just typed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt; because that’s the parameter type.&lt;/li&gt;
  &lt;li&gt;Load the constant &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Store the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; to the local named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xs&lt;/code&gt;, thus clearing it.  Note that in the locals table, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xs&lt;/code&gt;
has the type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt;. This means that when we get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xs&lt;/code&gt; from the local, we have to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkcast&lt;/code&gt; it
again because we’ve lost type information by storing and loading it.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkcast&lt;/code&gt; the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xs&lt;/code&gt; we loaded to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Iterable&lt;/code&gt; since we don’t really know what it is.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invokeinterface&lt;/code&gt; of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.iterator&lt;/code&gt; method to get an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Iterator&lt;/code&gt; from our now guaranteed
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Iterable&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Store our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Iterable&lt;/code&gt; into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iter&lt;/code&gt; local (discarding type information as above)&lt;/li&gt;
  &lt;li&gt;Load the constant &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; from the class constant pool.&lt;/li&gt;
  &lt;li&gt;Store the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tot&lt;/code&gt; local (primitive typed)&lt;/li&gt;
  &lt;li&gt;Load our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iter&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkcast&lt;/code&gt; because in storing it we forgot that it’s an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Iterator&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invokeinterface&lt;/code&gt; to see if there are elements left, producing a primitive &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;boolean&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Branch on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;boolean&lt;/code&gt; going to 21 (in this list) if false&lt;/li&gt;
  &lt;li&gt;Load &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tot&lt;/code&gt; from the local&lt;/li&gt;
  &lt;li&gt;Load &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iter&lt;/code&gt; from the local&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkcast&lt;/code&gt; that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iter&lt;/code&gt; is still &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Iterator&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invokeinterface&lt;/code&gt; to get the next value from the iterator, producing an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invokestatic&lt;/code&gt; to call the static &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.lang.RT&lt;/code&gt; method for converting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt;s to
primitive &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;long&lt;/code&gt;s.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invokestatic&lt;/code&gt; to add the two primitive &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;long&lt;/code&gt;s on the stack&lt;/li&gt;
  &lt;li&gt;Store the new value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tot&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Loop back to 10.&lt;/li&gt;
  &lt;li&gt;Clear the stack&lt;/li&gt;
  &lt;li&gt;Load &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tot&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;return&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So with the exception of the first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkcast&lt;/code&gt; to make sure that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt; we
got as an argument that &lt;em&gt;should&lt;/em&gt; be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Iterable&lt;/code&gt; is in fact an instance of
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Iterable&lt;/code&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkcast&lt;/code&gt;s after &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;load&lt;/code&gt; are all provably uncalled for. The
static types of these values is known because their Java signatures are known,
and the only reason that we have to emit all these checks is that the Compiler
throws that information away by storing these values in untyped (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt;)
locals.&lt;/p&gt;

&lt;h2 id=&quot;the-hack&quot;&gt;The Hack&lt;/h2&gt;

&lt;p&gt;Every
&lt;a href=&quot;https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L347-L355&quot;&gt;Expr&lt;/a&gt;
in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.lang.Compiler&lt;/code&gt; already knows (or can state) its type either as
tagged or inferred, and whether it has such a tag. However, these stated Java
classes are lies! A function invocation (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IFn.invoke&lt;/code&gt; call site) is statically
typed to return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt; (unless it’s a primitive call site but we know that as
well) no matter what the tag on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IFn&lt;/code&gt; being invoked may say. For example
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.core/str&lt;/code&gt; is tagged &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^String&lt;/code&gt; and does indeed return a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt;,
however after invoking the appropriate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IFn&lt;/code&gt; the JVM doesn’t know that there’s a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt; on the stack because the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IFn&lt;/code&gt; interface discards that type
information. It just knows it has an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt;. The fix is that we add a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expr.needsCast&lt;/code&gt; method and implement it for every instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expr&lt;/code&gt; in
Compiler.java. So now when in strict mode, we know that unless &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expr.needsCast&lt;/code&gt;
returns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;, the value on the stack after &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expr.emit&lt;/code&gt; absolutely is of type
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expr.getJavaClass&lt;/code&gt;. Otherwise we cannot avoid the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkcast&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We also have to change the behavior of locals so that we can emit locals with
types other than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt;. By typing locals we preserve their type information
as tagged or inferred across loads and stores. This allows the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expr&lt;/code&gt;
representing a local use to report that it only needs a cast when the usage of
the local doesn’t have the same tag as the type of the binding and we cannot
statically show no cast is required.&lt;/p&gt;

&lt;p&gt;With these changes, our modified Compiler.java can indeed produce and use
strictly typed locals. So lets add our annotation…&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:strict&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Iterable&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.iterator&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;loop&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tot&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.hasNext&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;recur&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tot&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.next&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And generate bytecode
&lt;strong&gt;on our modified version of Skummet 1.7-RC1-r4&lt;/strong&gt;
(again abbreviated).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public final long invokePrim(java.lang.Object);
  Code:
     0: aload_1
     1: aconst_null
     2: astore_1
     3: checkcast     #30                 // class java/lang/Iterable
     6: invokeinterface #34,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
    11: astore_2
    12: lconst_0
    13: nop
    14: lstore_3
    15: aload_2
    16: invokeinterface #40,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
    21: ifeq          43
    24: lload_3
    25: aload_2
    26: invokeinterface #44,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
    31: invokestatic  #49                 // Method clojure/lang/RT.longCast:(Ljava/lang/Object;)J
    34: ladd
    35: lstore_3
    36: goto          15
    39: goto          44
    42: pop
    43: lload_3
    44: lreturn
  LocalVariableTable:
    Start  Length  Slot  Name   Signature
       15      29     3   tot   J
       12      32     2  iter   Ljava/util/Iterator;
        0      44     0  this   Ljava/lang/Object;
        0      44     1    xs   Ljava/lang/Object;

public java.lang.Object invoke(java.lang.Object);
  Code:
     0: aload_0
     1: aload_1
     2: invokeinterface #59,  2           // InterfaceMethod clojure/lang/IFn$OL.invokePrim:(Ljava/lang/Object;)J
     7: new           #13                 // class java/lang/Long
    10: dup_x2
    11: dup_x2
    12: pop
    13: invokespecial #62                 // Method java/lang/Long.&quot;&amp;lt;init&amp;gt;&quot;:(J)V
    16: areturn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The win compared to the original bytecode should be obvious. Sure enough in the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;invokeStatic&lt;/code&gt; method we only emit the one checkcast we absolutely have to have
because the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xs&lt;/code&gt; argument could really be anything. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tot&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iter&lt;/code&gt; locals
are both statically typed, and so we can just load them and invoke the
appropriate interfaces directly.&lt;/p&gt;

&lt;p&gt;In some simple benchmarks, this optimization on this fn translates to a 5%-10%
performance improvement which isn’t too impressive. However other fns like
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.core/str&lt;/code&gt; in our testing were able to get up to 20% performance
improvements from strict locals.&lt;/p&gt;

&lt;h2 id=&quot;disclaimer&quot;&gt;Disclaimer&lt;/h2&gt;

&lt;p&gt;This is the product of a two day hack. While Alan and I have been able to get it
to work and emit working code, honestly this isn’t something we’re comfortable
taking to production yet. Some clear wins such as being able to emit typed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fn&lt;/code&gt;
arguments by popping arguments, checking them and then putting them in typed
local bindings for use and being able to take advantage of types on closed over
locals remain on the table.&lt;/p&gt;

&lt;h2 id=&quot;what-didnt-seem-to-work&quot;&gt;What Didn’t (seem) To Work&lt;/h2&gt;

&lt;p&gt;While Alan debugged Compiler.java and picked off some types related wins we
hadn’t gotten yet I worked on adding more inlining behavior to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.core&lt;/code&gt;. Much of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;core&lt;/code&gt;, especially the lexically early &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fn&lt;/code&gt;s are just
thin wrappers around interop on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.lang.RT&lt;/code&gt;, which does have reasonable
interface types on most of its methods.&lt;/p&gt;

&lt;p&gt;The hope was that what with the typed locals work, preserving more type
information across calls to the Clojure standard library and inlining the
Clojure standard library where possible to interop calls with clearly inferable
types we would be able to produce demonstrably faster code.&lt;/p&gt;

&lt;p&gt;While in theory this should be at least break even and probably a win, we
haven’t managed to benchmark it well and show a clear win from the aggressive
inlining work. In fact, the really interesting case of possibly aggressive
inlining being an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;into&lt;/code&gt; which is able to use a typed, static &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Transient&lt;/code&gt; loop
is impossible because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;into&lt;/code&gt; is implemented in terms of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reduce&lt;/code&gt;, which takes
the reducing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fn&lt;/code&gt; as a value and then dispatches via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.lang.IReduce&lt;/code&gt; in
order to get fast iteration over chunked seq. However we can’t statically inline
a call site through being taken as a value so that’s the end of the line for
that idea.&lt;/p&gt;

&lt;h2 id=&quot;inline-unrolling&quot;&gt;Inline Unrolling&lt;/h2&gt;

&lt;p&gt;We were however able to fully inline some interesting cases of
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.core/assoc&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.core/conj&lt;/code&gt;. A common pattern in Clojure is to
write a function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt; which has a zero arguments case returning a constant, a one
argument case returning the argument unmodified and a two or more arguments case
in which the operation &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt; is reduced over the arguments provided. Rather than
directly implement &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IFn&lt;/code&gt;, functions emitted by Clojure instead extend
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.lang.AFn&lt;/code&gt;
(&lt;a href=&quot;https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/AFn.java&quot;&gt;source&lt;/a&gt;),
which provides some out of the box support for functions of variable arity and
function application.&lt;/p&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h2&gt;

&lt;p&gt;These changes were motivated by internal performance requirements and will
likely get polished until they are ready to be upstreamed back to Skummet. While
we expect that the patch we have developed will never be included into Clojure
as-is if only due to high impact, we hope to see this behavior or something like
it enter the mainline in a future version of Clojure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edit 1&lt;/strong&gt;:
&lt;a href=&quot;https://github.com/alexander-yakushev/clojure/pull/1&quot;&gt;Skummet pull request submitted&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;^d&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Toothpick: A theory of bytecode machines</title>
    <link href="https://www.arrdem.com/2015/01/28/toothpick_a_theory_of_bytecode_machines/"/>
    <updated>2015-01-28T22:50:37+00:00</updated>
    <id>https://www.arrdem.com/2015/01/28/toothpick_a_theory_of_bytecode_machines</id>
    <content type="html">&lt;p&gt;In working on my &lt;a href=&quot;/2014/01/10/Batbridge/&quot;&gt;Batbridge&lt;/a&gt; simulators and other adventures in computing hardware, one of the problems I have repeatedly encountered is the need to generate bit encodings of symbolic instructions.
When working with “well known” architectures with existing tooling support, one can usually find an “off the shelf” assembler either in the GCC collection or elsewhere.
However when you’re working against a custom instruction set you’re on your own for tooling.&lt;/p&gt;

&lt;p&gt;So lets invent yet another assembler!&lt;/p&gt;

&lt;p&gt;An assembler is simply a program that describes how to construct a binary instruction encoding from a set of symbolic human-writable mnemonics representing data manipulating directives to computing hardware.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sub[tract]&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mul[tiply]&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jump&lt;/code&gt; are good examples of such mnemonics.
Each operation which a given “machine” (hardware/software interpreter) will accept is typically specified as a sequence of bits and bit encoded fields (sometimes abbreviated in octal or hexadecimal notation).
So Batbridge for instance specifies that the add instruction is the bit string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;110000tttttaaaaabbbbbiiiiiiiiiii&lt;/code&gt; where the prefix &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;110000&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x30&lt;/code&gt; indicates the addition operation, the bits named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t&lt;/code&gt; encode a number &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t∈[0..30]&lt;/code&gt; being the register to which the result of the addition will be stored, the bits named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; subject to the same constraints as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t&lt;/code&gt; name the register from which the “left” operand will be drawn and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt; bits name the “right” operand same as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; operands.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;i&lt;/code&gt; is an arbitrary signed 10 bit integer (sign is the 11th bit).&lt;/p&gt;

&lt;p&gt;Sitting down with &lt;a href=&quot;https://github.com/arrdem/batbridge/blob/master/doc/batbridge.md&quot;&gt;a specification&lt;/a&gt;, you or I could construct a set of functions from values appropriately constrained to bit encoded instructions as laid out in an instruction set specification.
However in doing such an assembler implementation, you will discover that you are simply encoding in the programming language of your choice a translation table laid out in full by the instruction set documentation.
However realizing that the assembler which we are constructing by hand represents a printer to the bytecode machine’s reader, we can think of bytecodes as a language in the same sense that any other set of strings and productions constitutes a language.&lt;/p&gt;

&lt;h2 id=&quot;a-theory-of-bytecode-machines&quot;&gt;A Theory of Bytecode Machines&lt;/h2&gt;

&lt;p&gt;It happens that we have good formal theories about languages and their structures.
If we stop and squint, we can see that the individual opcodes are analogous to terminals or verbs.
If we allow ourselves to model opcodes as words in a language, then a program (a production of words) is a sentence for which we can establish a grammar.
For instance a ELF formatted program could be considered to be a sequence of blocks of instructions (verbs) defined in terms of words (opcodes) and formatted with an appropriate header/footer (the ELF file structure).
As these are all linguistic constructs, a program capable of generating these values must be a direct production of the specification which lays out these productions in the same way that a lex/yacc lexer parser pair is a mechanical production of the lexing and parsing rules which define a computer language.&lt;/p&gt;

&lt;p&gt;This leads to the idea that, just as we now rarely write parsers and lexers preferring to derive them automatically from specifications of the languages we wish them to process since a as suggested above a bytecode is simply a language on bit strings rather than ASCII or Unicode characters the consequent that we can use the same class of tools to generate assemblers and disassemblers as we use to generate parsers and printers should be obvious.
We just need to construct formal languages describing the instructions our machines accept.&lt;/p&gt;

&lt;h2 id=&quot;an-assembler-generator&quot;&gt;An Assembler Generator&lt;/h2&gt;

&lt;p&gt;Just as we have theories about “interesting” sets of languages and the parser techniques which may be applied to efficiently recognize and process them, so too rather than being able to automatically assemble arbitrary programs to arbitrary bytecodes we must first recognize that as a bytecode is a language on bit strings and as there exist languages which require a Turing machine to recognize in addition to uncomputable languages consequently one could invent an “interesting” (but I will argue in a minute silly) bytecode for which no assembler or recognizer can be automatically generated.&lt;/p&gt;

&lt;p&gt;So what features define “interesting” bytecodes?
In hardware terms &lt;a href=&quot;/2014/01/01/Hardware-101/&quot;&gt;as I discuss elsewhere&lt;/a&gt; memories and lookup tables are just about the most expensive thing you can build in terms of chip area and time.
As a result, the overwhelming majority of computer architectures are not what I shall call “micro-programmable”, that is users cannot give meaning to new sequences of bits and rather interact with the computer by chaining together a few bit-verbs or opcodes which are built into the chip.
There do exist such micro-programmable computers, FPGAs, but they tend to be special purpose prototyping machines and are not in wide usage compared to fixed instruction set machines.&lt;/p&gt;

&lt;p&gt;Another characteristic of “interesting” bytecodes is in the name, bytes or words.
Many years have gone by since bit addressed machines were last built with commercial intent.
Instead commercial machines and off the shelf memories tend to address “blocks” of bits or “lines” being strings a power of two in length which may be divided into substrings smaller powers of two in length as the user may see fit at no additional hardware complexity cost by simply selecting bits through selecting predefined subdivisions of lines known as “words” or using bit masking and shifting to select strings smaller than a single word.
Strings larger than a single word must be dealt with by using multiple operations on words.&lt;/p&gt;

&lt;p&gt;This theory of a fixed word size, fixed instruction set machine characterizes the overwhelming majority of instruction sets and machines designed and built by Intel, ARM, Symbolics, Thinking Machines, and others over the past decades due mainly to the ease of implementation and efficiency of such designs.&lt;/p&gt;

&lt;p&gt;So what does this theory about a “useful” bytecode machine buy us?
It implies that we can describe a “useful” machine as a bitstring length denoting word size.
Endianness must also be considered.
Then given an enumeration of the various opcodes and how to generate them as bitstrings, you can completely describe an “interesting” instruction set as characterized above.&lt;/p&gt;

&lt;p&gt;Assemblers are simply programs that deal with translating instructions set mnemonics writable by a programmer or more often than not a compiler to bytecodes which a machine can execute.
The details of computing label addresses are entirely for the most part independent of the specific architecture in so much as they are determined by properties of the specific target bytecode described above.
This suggests that there must exist a function&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(assemble p ← Platform c ← Codes)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Which makes sense if you consider a single target assembler to be the partial application of such an assembler to a platform.&lt;/p&gt;

&lt;h2 id=&quot;talk-is-cheap-show-me-the-code&quot;&gt;Talk is cheap, show me the code&lt;/h2&gt;

&lt;p&gt;First things first, we need a way to represent an “interesting” instruction set.&lt;/p&gt;

&lt;div class=&quot;language-clojure highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;deftype&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Architecture&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A structure representing an \&quot;interesting\&quot; bytecode architecture
    from which a parser or a generator can be computed.&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word-width&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;         &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; ← Num, how many bits in a word&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pointer-resolution&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; ← Num, how many bits forwards does *(x+1) go&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;opcodes&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; ← Map [Memonic → Opcode], opcode formatting rules&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So what do individual opcodes look like?
We’re gonna need some bit vector formatting engine to do real code bytecode generation with.&lt;/p&gt;

&lt;p&gt;I will define an opcode to be a bitstring &lt;em&gt;of fixed length&lt;/em&gt; (this is important, there are instruction sets with variable length “opcodes” however as the different length forms have different operational semantics I shall define them to be different operations and declare the instruction set architects silly people) composed of a sequence of concatenated parameters or fields and constants which may be either signed or unsigned.
Fields are named or anonymous.
The set of named field names in a single opcode must have no repetitions.
We want to be able to write something like the following&lt;/p&gt;

&lt;div class=&quot;language-clojure highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;;; IFLT 0x20  100000 _____ aaaaa bbbbb iiiiiiiiiii&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;;; execute the next instruction IFF (&amp;lt; a b)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;opcode&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:iflt&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;const-field&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:icode&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;enforced-const-field&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:_&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;     &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parameter-field&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;     &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parameter-field&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;     &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;signed-parameter-field&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:i&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;     &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;literal?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So in this example instruction from Batbridge, we define an instruction as the ordered bit string where the bits &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[0..5]&lt;/code&gt; are named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:icode&lt;/code&gt; and fixed with the constant value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x20&lt;/code&gt;.
We then have an anonymous field 5 bits long taking the bits &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[6..10]&lt;/code&gt; which we force to have the value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; since they are defined to be ignored by the instruction set.
We then have a pair of (unsigned) 5-bit registers, which must satisfy some guard predicate ensuring that the value in question fits within the value domain which the instruction set allows for registers.
Finally we have a signed field 11 bits long, which again is guarded with a value domain predicate.
This notation encodes the bit format string, as well as the value domains for each element of the bit format string in a form that can be easily inspected by either an assembler or a disassembler program.&lt;/p&gt;

&lt;p&gt;So what does that expression build out to as a data structure?&lt;/p&gt;

&lt;div class=&quot;language-clojure highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:width&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:params&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:_&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:fields&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:offset&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:width&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:icode,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:const,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:value&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:offset&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:width&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:_,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:enforced-const,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:value&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:offset&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:width&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:a,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:unsigned-field,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:pred&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;&amp;lt;batbridge$register_QMARK_&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;toothpick.isa.batbridge$register_QMARK_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bd4095&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:offset&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:width&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:b,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:unsigned-field,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:pred&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;&amp;lt;batbridge$register_QMARK_&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;toothpick.isa.batbridge$register_QMARK_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bd4095&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:offset&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:width&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:i,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:signed-field,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
           &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:pred&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;&amp;lt;batbridge$literal_QMARK_&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;toothpick.isa.batbridge$literal_QMARK_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;38334886&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Given this datastructure, and a sequence &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(opcode . params)&lt;/code&gt;, we can trivially compute a map &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(zipmap (:params (get isa opcode)) params)&lt;/code&gt;, and then fold right over the fields of the instruction computing each field then shifting and anding it into place in the bit vector to construct the bit encoding of the instruction.&lt;/p&gt;

&lt;p&gt;As implemented this is a little fragile because it assumes that the computer running the assembler assembler has a larger or equal integer size than the target, as attempting to construct an int aka bit vector that’s too large will yield…
interesting issues.
Future fixes are to use a real sequence of bits, or to rewrite this logic in terms of multiplication by two and addition.&lt;/p&gt;

&lt;p&gt;Deriving a parser for this structure is also (fairly) straightforwards, one simply can simply generate an alternation matcher on bitstring matchers matching the individual instructions.
“interesting” ISAs tend to put the opcode specification in the “low” bits of each instruction word so as a we can simply generate a jump table by masking on the least significant bits but that’s not implemented yet.&lt;/p&gt;

&lt;p&gt;Also this representation falls into &lt;a href=&quot;http://www.jneen.net/&quot;&gt;jneen&lt;/a&gt;’s &lt;a href=&quot;https://www.youtube.com/watch?v=ZQkIWWTygio&quot;&gt;type tagging pitfall&lt;/a&gt;, but this is old code and implementation details thereof so I’ll forgive myself and fix it later.&lt;/p&gt;

&lt;p&gt;We can then define an “architecture” by constructing a composite map as above having a word size and pointer interval specification and a map from keywords naming instructions to many such instruction maps.&lt;/p&gt;

&lt;p&gt;So, we can describe an instruction stream as a sequence of instructions, and we can assemble individual instructions by interpreting from their representation above, so if we wanted to encode a sample program&lt;/p&gt;

&lt;div class=&quot;language-clojure highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:label&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:top&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:op&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:add&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:param&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:register&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:param&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:param&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:label&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:op&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:add&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:param&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:register&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:param&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:param&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:label&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:op&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:add&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:param&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:register&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:param&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:register&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:param&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:register&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:label&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can simply foldr a label location computing operation since all of our opcodes are defined to be fixed length even if they are abstractly variable length, then in a second pass we assemble each instruction against the label location context and the instruction set, giving us a sequence of bytecodes.
Done!
∎&lt;/p&gt;

&lt;p&gt;This is essentially my &lt;a href=&quot;https://github.com/arrdem/toothpick&quot;&gt;Toothpick&lt;/a&gt; project, which seeks to provide exactly this meta-assembler facility and has already proven its worth to me in automating the generation of assemblers for the various toy architectures with which I’ve worked at school.
It’s not done yet and as noted above it needs some spit and shoeshine but I think it represents a remarkably simple and powerful idea.&lt;/p&gt;

&lt;p&gt;The real power of this approach is that, extended, this can enable the automatic generation of LLVM backends!
If an instruction specification were to include its operational semantics written in terms of LLVM instructions one could imagine a trivial derived LLVM backed which sequentially scans emitted LLVM assembly matching out the platform translation of the instruction “at point” and then assembling the resulting instruction stream as above.
Since LLVM already provides a massively portable C compiler infrastructure, this means that given only a formal platform specification one could construct a mediocre C compiler only from the platform specification.&lt;/p&gt;

&lt;p&gt;To take this idea even further, one could also imagine generating a platform simulator from either symbolic instructions or bit encoded instructions from only the augmented ISA with semantics instructions.&lt;/p&gt;

&lt;p&gt;Generating muxing logic in Verilog or VHDL should also be trivial from this structure.&lt;/p&gt;

&lt;p&gt;Generate all the things!
Correctness by specification &amp;amp; construction!
Toy architectures for everyone!&lt;/p&gt;

&lt;p&gt;^d&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Oxcart going forwards</title>
    <link href="https://www.arrdem.com/2014/12/11/oxcart_going_forwards/"/>
    <updated>2014-12-11T14:35:07+00:00</updated>
    <id>https://www.arrdem.com/2014/12/11/oxcart_going_forwards</id>
    <content type="html">&lt;p&gt;When I &lt;a href=&quot;/2014/08/06/of_oxen,_carts_and_ordering/&quot;&gt;last wrote&lt;/a&gt; about
&lt;a href=&quot;https://github.com/oxlang/oxcart&quot;&gt;Oxcart&lt;/a&gt; work pretty much went on hiatus due
to my return to school. As there has been some recent interest in the status of
Lean Clojure overall I thought I’d take the opportunity to review the state of
Oxcart and the plan for Oxcart going forwards.&lt;/p&gt;

&lt;h2 id=&quot;oxcart-and-clojure&quot;&gt;Oxcart and Clojure&lt;/h2&gt;

&lt;p&gt;The static linking approach and lack of run time dynamism found in Oxcart is
explicitly at odds with the philosophy of core Clojure. Where Clojure was
designed to enable live development and makes performance sacrifices to enable
such development
&lt;a href=&quot;http://stackoverflow.com/questions/27388758/what-is-the-difference-between-clojure-repl-and-scala-repl/27391533#27391533&quot;&gt;as discussed here&lt;/a&gt;,
Oxcart attempts to offer the complement set of trade offs. Oxcart is intended as
a pre-deployment static compiler designed to take a working application and to
the greatest extent possible wring more performance out of unchanged (but
restricted) Clojure as PyPy does for Python. As Oxcart explicitly avoids the
dynamic bindings which Clojure embraces,
&lt;a href=&quot;http://tech.puredanger.com/&quot;&gt;Alex Miller&lt;/a&gt;, the Clojure Community Manager, has
repeatedly stated that he expects to see little cross pollination from Oxcart
and related work to Clojure itself.&lt;/p&gt;

&lt;p&gt;This would be all well and good, were it not for the existing behavior of
Clojure’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.lang.RT&lt;/code&gt; class. As currently implemented in Clojure 1.6 and
1.7, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RT&lt;/code&gt; uses its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;initc&amp;gt;&lt;/code&gt; method to compile the following resources with
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.lang.Compiler&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;“clojure/core”&lt;/li&gt;
  &lt;li&gt;“clojure/core_proxy”&lt;/li&gt;
  &lt;li&gt;“clojure/core_print”&lt;/li&gt;
  &lt;li&gt;“clojure/genclass”&lt;/li&gt;
  &lt;li&gt;“clojure/core_deftype”&lt;/li&gt;
  &lt;li&gt;“clojure/core/protocols”&lt;/li&gt;
  &lt;li&gt;“clojure/gvec”&lt;/li&gt;
  &lt;li&gt;“clojure/instant”&lt;/li&gt;
  &lt;li&gt;“clojure/uuid”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These represent about 10799 lines of code, all of which could easily be
statically compiled and most importantly tree shaken ahead of time by Oxcart or
another tool rather than being loaded at boot time. This also means that the
unavoidable booting of Clojure itself from source can easily dominate loading
user programs especially after static compilation to raw classes. A quick
benchmark on my machine shows that booting a Clojure 1.6 instance, loading a ns
containing only a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-main&lt;/code&gt; that only prints “hello world” takes ~2.8 seconds from
source compared to ~2.5 seconds booting the same program compiled with Oxcart
suggesting that the cost of booting Clojure is the shared ~2.5 second boot
time. This is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test.hello&lt;/code&gt; benchmark in
&lt;a href=&quot;https://github.com/oxlang/oxcart#demos&quot;&gt;Oxcart’s demos&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git clone git@github.com:oxlang/oxcart.git &amp;amp;&amp;amp;\
  cd oxcart &amp;amp;&amp;amp;\
  git checkout 0.1.2 &amp;amp;&amp;amp;\
  bash bench.sh test.hello
Running Clojure 1.6.0 compiled test.hello....
Hello, World!

real    0m1.369s
user    0m3.117s
sys     0m0.083s
Oxcart compiling test.hello....
Running Oxcart compiled test.hello....
Hello, World!

real    0m1.212s
user    0m2.487s
sys     0m0.073s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then there’s the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test.load&lt;/code&gt; benchmark. This benchmark as-is pushes credulity
because it compiles 502 functions of which only the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-main&lt;/code&gt; which uses none of
the other 501 will be invoked. This reflects more on program loading time than
on the loading time of “clojure/core”, but I still think instructive in the
costs of boot time compilation, showing a ~7s boot time for Clojure compared to
a ~2.5s boot time for Oxcart. As arbitrary slowdowns from macroexpansions which
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Thread/sleep&lt;/code&gt; would be entirely possible I consider this program within the
bounds of “fairness”.&lt;/p&gt;

&lt;h2 id=&quot;a-fork-in-the-road&quot;&gt;A Fork in the Road&lt;/h2&gt;

&lt;p&gt;There are two solutions to this limitation, and both of them involve changing
the behavior of Clojure itself. The first is my proposed
&lt;a href=&quot;https://groups.google.com/forum/#!searchin/clojure-dev/lib-clojure/clojure-dev/dSPUNKSaV94/gTikbqYhJTYJ&quot;&gt;lib-clojure&lt;/a&gt;
refactor. Partitioning Clojure is a bit extreme, and in toying with the proposed
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RT&lt;/code&gt; → &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Util&lt;/code&gt; changes &lt;a href=&quot;https://github.com/arrdem/clojure/tree/arrdem&quot;&gt;over here&lt;/a&gt;
I’ve found that they work quite nicely even with a monolithic Clojure
artifact. Unfortunately there seems to be little interest from Clojure’s Core
team (as judged via Alex’s communications over the last few months) in these
specific changes or in the static compilation approach to reducing the
deployment overhead of Clojure programs. The second is to fork Clojure and then
make lib-clojure changes which solves the problem of convincing Core that
lib-clojure is a good idea but brings its own suite of problems.&lt;/p&gt;

&lt;p&gt;Oxcart was intended to be my undergraduate thesis work. While the 16-25% speedup
previously reported is impressive, Oxcart does nothing novel or even interesting
under the hood. It only performs four real program transformations:
&lt;a href=&quot;http://en.wikipedia.org/wiki/Lambda_lifting&quot;&gt;lambda lifting&lt;/a&gt;, two kinds of
static call site linking and
&lt;a href=&quot;http://en.wikipedia.org/wiki/Unreachable_code&quot;&gt;tree shaking&lt;/a&gt;. While I suppose
impressive for an undergrad, this project also leaves a lot on the table in
terms of potential utility due to its inability to alter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RT&lt;/code&gt;’s unfortunate
loading behavior. I also think there is low hanging fruit in doing unreachable
form elimination and effect analysis, probably enough that Oxcart as-is would
not be “complete” even were its emitter more stable.&lt;/p&gt;

&lt;p&gt;I’m reluctant to simply fork Clojure, mainly because I don’t think that the
changes I’ve been kicking about for lib-clojure actually add anything to Clojure
as a language. If I were to fork Clojure, it’d be for
&lt;a href=&quot;/2014/09/10/ox_a_preface/&quot;&gt;Oxlang&lt;/a&gt;
which actually seeks to make major changes to Clojure not just tweak some
plumbing. But writing a language so I can write a compiler is frankly silly so
that’s not high on the options list. The worst part of this is that forking
Clojure makes everything about using Oxcart harder. Now you have dependencies at
build time (all of “stock” Clojure) that don’t exist at deployment time (my
“hacked” Clojure). Whatever hack that requires either winds up complicating
everyone’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;project.clj&lt;/code&gt; or in an otherwise uncalled for leiningen plugin just
like &lt;a href=&quot;https://github.com/alexander-yakushev/lein-skummet&quot;&gt;lein-skummet&lt;/a&gt;. Tooling
needs to be able to get around this too when every library you’d want to use
explicitly requires &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[org.clojure/clojure ...]&lt;/code&gt; which totally goes away once
Oxcart emits the bits you need and throws the rest out. Most of all I don’t want
to maintain a fork for feature parity as time goes on. However I also don’t see
any other a way to get around &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RT&lt;/code&gt;’s existing behavior since the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RT&lt;/code&gt; → &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Util&lt;/code&gt;
refactor touches almost every java file in Clojure.&lt;/p&gt;

&lt;h2 id=&quot;flaws-in-the-stone&quot;&gt;Flaws in the Stone&lt;/h2&gt;

&lt;p&gt;Oxcart itself also needs a bunch of work. While I think that Nicola has done an
awesome job with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools.analyzer&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools.emitter.jvm&lt;/code&gt; I’m presently
convinced that while it’s fine for a naive emitter (what TEJVM is), it’s a
sub-optimal substrate for a whole program representation and for whole program
transforms.&lt;/p&gt;

&lt;p&gt;Consider renaming a local symbol. In the LLVM compiler infrastructure, “locals”
and other program entities are represented as mutable nodes to which references
are held by clients (say call sites or use sites). A rename is then simply an
update in place on the node to be changed. All clients see the change with no
change in state. This makes replacements, renames and so forth constant time
updates. Unfortunately due to the program model used by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools.analyzer&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools.emitter.jvm&lt;/code&gt;, such efficient updates are not possible. Instead most
rewrites degenerate into worst case traversals of the entire program AST when
they could be much more limited in
scope. &lt;a href=&quot;https://github.com/oxlang/cutaway&quot;&gt;Cutaway&lt;/a&gt; is one experiment in this
direction, but it at best approximates what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.core.logic.pldb&lt;/code&gt; is capable
of. I hope that over Christmas I’ll have time to play with using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pldb&lt;/code&gt; to
store, search and rewrite a “flattened” form of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools.analyzer&lt;/code&gt; ASTs.&lt;/p&gt;

&lt;p&gt;Oxcart is out of date with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools.emitter.jvm&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools.analyzer&lt;/code&gt;. This
shouldn’t be hard to fix, but I just haven’t kept up with Nicola’s ongoing work
over the course of the last semester. This will probably get done over Christmas
as well.&lt;/p&gt;

&lt;p&gt;Oxcart doesn’t support a bunch of stuff. As of right now, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;defmulti&lt;/code&gt;,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;defmethod&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deftype&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;defprotocol&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proxy&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extend-type&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extend-protocol&lt;/code&gt; aren’t supported. I’m pretty sure all of these actually work,
or could easily work, they just didn’t get done in the GSoC time frame.&lt;/p&gt;

&lt;p&gt;Finally and I think this is the thing that’s really blocking me from working on
Oxcart: it can’t compile &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.core&lt;/code&gt; anyway. This is a huge failing on my
part in terms of emitter completeness, but it’s a moot point because even if I
can compile &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clojure.core&lt;/code&gt; with Oxcart &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RT&lt;/code&gt; is gonna load it anyway at boot
time. I also suspect that this is an incompleteness in the project as a whole
which probably makes it an unacceptable thesis submission although I haven’t
spoken with my adviser about it yet.&lt;/p&gt;

&lt;h2 id=&quot;the-endgame&quot;&gt;The Endgame&lt;/h2&gt;

&lt;p&gt;As of right now I think it’s fair to call Oxcart abandoned. I don’t think it’s a
worthwhile investment of my time to build and maintain a language fork that
doesn’t have to be a fork. I talked with &lt;a href=&quot;http://www.bytopia.org/&quot;&gt;Alexander&lt;/a&gt;,
one of the clojure-android developers and a fellow GSoC Lean Clojure
student/researcher about this stuff and the agreement we reached was that until
1.7 is released there’s no way that the lib-clojure changes will even get
considered and that the most productive thing we can do as community members is
probably to wait for 1.8 planning and then try to sell lib-clojure and related
cleanup work on the basis of enabling clojure-android and lean
clojure/Oxcart. Practically speaking in terms of my time however, if it’s going
to be a few months until 1.7 and then a year until 1.8, that only gives leaves
me my last semester of college to work on Oxcart against an official version of
Clojure that can really support it. If that’s what it takes to do Oxcart I’ll
likely just find a different thesis project or plan on graduating without a
thesis.&lt;/p&gt;

&lt;pre&gt;
(with-plug
  That said, serious interest in Oxcart as a deployment tool or another
  contributor would probably be enough to push me over the futility hump
  of dealing with a Clojure fork and get Oxcart rolling.)
&lt;/pre&gt;

&lt;p&gt;^d&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The Future of the LispM</title>
    <link href="https://www.arrdem.com/2014/11/28/the_future_of_the_lispm/"/>
    <updated>2014-11-28T05:10:38+00:00</updated>
    <id>https://www.arrdem.com/2014/11/28/the_future_of_the_lispm</id>
    <content type="html">&lt;p&gt;This is also addressed to &lt;a href=&quot;https://twitter.com/lojikil&quot;&gt;@lojikil&lt;/a&gt; towards whom I have threatened to write this post on multiple occasions.
It is expected to piss off &lt;a href=&quot;http://loper-os.org&quot;&gt;loper-os&lt;/a&gt;.
Above all, it represents my opinions backed up only by a cursory research effort.
You have been warned.&lt;/p&gt;

&lt;h2 id=&quot;background-of-historical-lispms&quot;&gt;Background Of Historical LispMs&lt;/h2&gt;

&lt;p&gt;LispMs occupy a transitional period of computing industry history between time shared mainframes and the single user workstations that would become today’s desktop computers.
Prior to John McCarthy’s invention of time sharing, all computers had been single program machines which multiple users shared via batch scheduling.
The introduction of time sharing opened the way to exploring how to make computers useful interactively for many users sitting at terminals.
Under bach processing, users would present fully formed programs written by hand or with little tool assistance to computer techs who would run the programs and return printed output.&lt;/p&gt;

&lt;p&gt;The concept of time sharing and interactivity lead to the development of more dynamic programming environments including the Read Eval Print Loop.
However at the same time, the falling costs of integrated circuits (and DoD funding for research into the design of such VLSI machines) began to put the first workstations, single user machines featuring large memories, within the financial reach of well funded AI laboratories which previously dependent on time shared mainframes.&lt;/p&gt;

&lt;p&gt;In order to improve interactive performance, Richard Greenblatt and Thomas Knight developed the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cons&lt;/code&gt; machine, the first of the MIT Lisp machines.
Priced at ~$50,000 in 1970s dollars &lt;a href=&quot;ftp://publications.ai.mit.edu/ai-publications/pdf/AIM-444.pdf&quot;&gt;cons&lt;/a&gt; and the successor &lt;a href=&quot;ftp://publications.ai.mit.edu/ai-publications/pdf/AIM-528.pdf&quot;&gt;cadr&lt;/a&gt; machine were single user workstations built primarily it seems to address the restrictions on memory and memory performance and subsequent detrimental impact on general program performance faced on time shared systems due to the large memory footprint of Lisp programs and page thrashing.
Hardware/microcode support was added for maintaining the relatively complex Lisp environment structures, and for many of the primitive lookup/load/store operations on cons cell structures that characterize a traditional Lisp implementation’s data access pattern.
This combination of machine support and microcoding enabled Lisp “compilers” to be far simpler and offloaded the responsibility for maintaining complicated structures such as the environment from the compiler to the microcode system.
Best of all as the microcode closely corresponded relatively directly to Lisp, on the rare occasions that truly writing microcode for say device drivers was called for doing so was easy because users could transparently invoke and define microcode from their native Lisp environment.&lt;/p&gt;

&lt;p&gt;Seeing a business opportunity, in the early ’80s a number of MIT AI lab researchers departed and founded Symbolics Inc.
and Lisp Machines Inc.
for the purpose of building and selling Knight machine derived Lisp workstations.
Ultimately however, Lisp machines did fall out of favor during the AI winter(s) and lost to what we now call the personal computer.
I have seen the argument made that they were too big-ticket and missed the mass market as a result.
Thus our story really begins.&lt;/p&gt;

&lt;div id=&quot;of-modern-hardware&quot;&gt;&lt;/div&gt;
&lt;h2 id=&quot;of-modern-hardware&quot;&gt;Of Modern Hardware&lt;/h2&gt;

&lt;p&gt;In the years since the demise of the dedicated LispMs, Intel and the other major chip manufacturers have progressed from single cycle to pipelined, cache accelerated, superscalar and out of order machines.
Knowledge of these designs is assumed.
I suggest my &lt;a href=&quot;/2014/01/10/Batbridge/&quot;&gt;earlier introduction series&lt;/a&gt; to these topics if you are not already familiar with them.
At a high level however, each step of this progression trades off chip area, transistors (complexity) and power budget to wring more instruction level parallelism out of existing programs.&lt;/p&gt;

&lt;p&gt;The Symbolics 3600 technical report from ‘83 claims a best case cycle time of 180ns (~5MHz) and a worst case of 250ns (4MHz).
Arbitrary reads from main memory are priced at 600ns (3x the cost of a single instruction).
This low (by modern standards) slowdown between the processor and memory meant that one could write programs that did lots and lots of random memory access and still have reasonable performance expectations.
However, as a stack machine architecture, there is no opportunity for the instruction level parallelism exploited by modern architectures as the exact state of the stack which is depended on by every instruction changes with every instruction.
This forces all program execution to wait during slow operations like main memory reads, division and floating point math due to the sequential data dependency on the stack.
This is a fundamental architectural failure common to all stack machines and skirted by modern software stack machines like the JVM by compiling literal stack instructions to a register machine in order to recover instruction level parallelism.&lt;/p&gt;

&lt;p&gt;Modern processors claim cycle times of 0.3̅ns for a 3GHz machine, often running multiple instructions per cycle.
Unfortunately while processors core clocks have gotten faster since the days of the 3600, memories have not fundamentally improved.
On modern hardware, 100ns for a random main memory read seems to be more or less normal.
This represents a 27x speedup in processor speed mismatched with a 6x speedup in main memory latency for an effective 4.5x slowdown on memory reads.
Now this is admittedly worst case memory latency.
Thanks to the L1 and L2 cache layers, memory read times of 1ns to 3ns are not uncommon meaning that for cache efficient programs it is quite reasonable to expect less than a 2ns or 6 cycles for memory reads hitting in the L1 or L2 cache.&lt;/p&gt;

&lt;p&gt;I mention this, because techniques like &lt;a href=&quot;http://cpsc.yale.edu/sites/default/files/files/tr362.pdf&quot;&gt;cdr coding&lt;/a&gt; serve to bring the average case of list access and construction down from their worst case behavior of generating massive heap fragmentation (and thus defeating caching and prefetching) towards the behavior of nicely caching sequential data layouts (classical arrays) typically via &lt;a href=&quot;http://www.hypirion.com/musings/understanding-persistent-vector-pt-1&quot;&gt;tree like structures&lt;/a&gt; or &lt;a href=&quot;http://srfi.schemers.org/srfi-101/srfi-101.html&quot;&gt;SRFI-101&lt;/a&gt;.
While traditional linked list structures due to potential heap fragmentation provide potentially atrocious cache locality and this cripple the performance of modern cache accelerated machines, more modern datastructures can simultaneously provide the traditional cons list pattern while improving cache locality and thus performance characteristics.
&lt;a href=&quot;http://vimeo.com/6624203&quot;&gt;Guy Steele himself&lt;/a&gt; has even come out arguing this point.&lt;/p&gt;

&lt;p&gt;Without literal implementation as a stack machine traversing linked lists and providing special hardware support for binding and soforth, the LispM instantly looses much of the vaunted simplicity which makes it attractive to program directly and becomes simply another register machine in the mold of modern ARM or Intel machines with strange long running microcoded instructions reminiscent more of the VAXen than of modern RISC inspired processors.
In short due to the many performance limitations of linked lists as data structures we as an industry will never again build machines as the original LispMs were for the sole purpose of traversing and manipulating linked list data structures.
Modern hardware simply offers better performance with more general applicability.&lt;/p&gt;

&lt;h2 id=&quot;of-modern-languages&quot;&gt;Of Modern Languages&lt;/h2&gt;

&lt;p&gt;We’ve also come a long way in language design and implementation.
Compilers, once slow, have gotten faster and smarter.
Virtual machines like the JVM, JavaScript and the CLR are becoming widely used deployment targets.
The ML and Haskell families of languages have introduced us to concepts of real abstract types and abstract effects which can be used to build programs coupled only by the abstract properties of the data being consumed, generated and effects produced.
Type inference is even making such fancy behavior manageable by mere mortals, while providing language implementations with more and more information with which to perform both program level optimization and micro-optimization not possible in traditional naive lisps.&lt;/p&gt;

&lt;h2 id=&quot;of-lispms-future&quot;&gt;Of LispMs Future&lt;/h2&gt;

&lt;p&gt;While we’ll never build a hardware LispM again, I suspect that we will see LispM like systems return one day in the not too distant future.
Not as hardware, but as software or a virtual machine designed to run atop existing and entirely adequate modern hardware.
Now in 10 years someone may make a commercial hardware LispM at which point I will be happy to eat my words, but as of right now I don’t see it happening.&lt;/p&gt;

&lt;p&gt;The JVM and the .net CLR have proven to be amazing platforms.
While their allocation requirements perhaps prohibit their use for implementing operating systems and driver code (&lt;a href=&quot;http://research.microsoft.com/en-us/projects/singularity/&quot;&gt;not&lt;/a&gt; &lt;a href=&quot;http://cosmos.codeplex.com/&quot;&gt;that&lt;/a&gt; &lt;a href=&quot;http://www.jnode.org/&quot;&gt;people&lt;/a&gt; &lt;a href=&quot;https://github.com/jtauber/cleese/&quot;&gt;haven’t&lt;/a&gt; &lt;a href=&quot;http://www.barrelfish.org/&quot;&gt;tried&lt;/a&gt; this sort of thing) they do offer excellent and standardized platforms.
It is my personal belief that, by leveraging the flexibility that Lisp dialects have for both data driven DSLs and macro DSLs that it would be more or less trivial to implement an operating system using a DSL for generating platform specific assembly.
As the “kernel” OS is implemented in the final “host” LispM language editing the kernel is possible albeit difficult due to the inherent difficulties of hot swapping operating systems.&lt;/p&gt;

&lt;p&gt;Add a JIT (no this isn’t easy), preferably implemented in the same assembler DSL as the host operating system, and the stage is set for building a LispM environment as a virtual machine running atop modern hardware and using modern JIT to achieve reasonable performance characteristics.
From this vantage the way is clear to implementing the rest of the operating system and user land in a fully fledged lisp with good reloading and introspection support atop this kernel of a JIT and enough of an OS to provide memory and process management.&lt;/p&gt;

&lt;p&gt;This is, I think, an entirely reasonable and practical project for a smallish (~3 or fewer) team and a single target architecture (Intel).
There was a project, &lt;a href=&quot;https://web.archive.org/web/20120702085030/http://www.stripedgazelle.org/joey/dreamos.html&quot;&gt;Dream&lt;/a&gt;, an &lt;a href=&quot;http://people.csail.mit.edu/jaffer/r4rs_toc.html&quot;&gt;r4rs&lt;/a&gt; x86 assembler dsl in which an r4rs interpreter and operating system were implemented.
It booted and worked more or less fine, and while it lacked polish I think it serves as an excellent proof of concept that such a self hosting Lisp &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(assembler os runtime)&lt;/code&gt; triple is viable.
I don’t argue that such an implementation will be trivially portable to a wide variety of target hardware because as experience shows porting nominally portable Linux, FreeBSD or FreeRTOS is actually quite hard and porting a JIT can at best be as hard due to tight coupling with the specific behavior of the target machine but this is why we specify an abstract machine and then let implementations deal with the mess as the JVM does.&lt;/p&gt;

&lt;p&gt;I also think that Lisp as a language family could stand to learn some new tricks if someone were to make the effort to build a full Lispy OS/VM thing.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://clojure.org&quot;&gt;Clojure&lt;/a&gt; is awesome.
I’ve written a boatload of it.
It’s an amazingly simple and elegant tool, and its persistent/immutable datastructures are absolutely worth stealing as is its concept of hygenic macros via symbol qualification and probably the concept of protocols/interfaces which Clojure kinda inherits from its primary host Java.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://http://racket-lang.org/&quot;&gt;Racket&lt;/a&gt; is also awesome although I can’t claim to have written a bunch of it.
Its approach to static compilation, strong support for documentation and examples via &lt;a href=&quot;http://docs.racket-lang.org/scribble-pp/index.html&quot;&gt;Scribble&lt;/a&gt;, its pattern matching and typechecking facilities are totally worth stealing.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.shenlanguage.org/&quot;&gt;Shen&lt;/a&gt; is interesting if only due to its built in Prolog engine enabling search for arbitrary proofs with regards to arbitrary program properties.
While criticized by the Haskell community for disregarding completeness being able to write and search for proofs with regards to arbitrary properties of programs not just types is I think an amazingly powerful one albeit an active research area.&lt;/p&gt;

&lt;h2 id=&quot;but-is-it-a-lispm&quot;&gt;But is it a LispM?&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://www.loper-os.org/?p=42&quot;&gt;There are some people&lt;/a&gt; who will rail against this vision of mine that the “OS” is as low as we need to try and push a language.
To my mind, the advantages of pushing a language to the hardware level are scant enough as argued above that it simply does not justify the investment or the delay.
Even the OS may be too low to push a language and that while the adventure of building an OS with a language to host the language ala &lt;a href=&quot;http://www.oberon.ethz.ch/&quot;&gt;Oberon&lt;/a&gt; because while integrating the language with the OS does offer maximal conceptual unity across the combined platform and provide a huge leap in ease of integrating pipelines of different applications it also forcibly discards programs not written in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HOST_LANG&lt;/code&gt; for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HOST_PLATFORM&lt;/code&gt;.
This is a problem if only because the Unix model of computing as implemented on Linux with the help of the GNU user land is second only to the mach hiding inside of Mac OS X in terms of apparent developer adoption.
Developers booting the next Dream for the first time won’t find familiar text editors or tools.
It will be a brave new world.&lt;/p&gt;

&lt;p&gt;Maybe that’s a good thing.
Maybe we can escape the legacy of Unix with untyped byte streams and instead revive some of Plan 9 with a basis in lispy goodness and with more types everywhere.
Maybe there’s even a place in this for algebraic effects.
Maybe we can join &lt;a href=&quot;http://doc.urbit.org/&quot;&gt;urbit&lt;/a&gt; in looking towards a functional, fully netwoked future.
Maybe.
If only we can look past the obsolete machines and operating systems of yesteryear with which we seem content to circlejerk and move forwards with appropriate context and vision.&lt;/p&gt;

&lt;p&gt;Or maybe we’ll just be stuck with Linux, Unix, OpenSSL and the rest of our somewhat suspect tower of legacy code out of sheer inertia and continue getting caught up in language of the month rages out of collective ADD.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; We have not wings, we cannot soar;
       But we have feet to scale and climb
 By slow degrees, by more and more,
       The cloudy summits of our time.

 The mighty pyramids of stone
       That wedge-like cleave the desert airs,
 When nearer seen, and better known,
       Are but gigantic flights of stairs.

 The distant mountains, that uprear
       Their solid bastions to the skies,
 Are crossed by pathways, that appear
       As we to higher levels rise.

 The heights by great men reached and kept
       Were not attained by sudden flight,
 But they, while their companions slept,
       Were toiling upward in the night.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;~ &lt;a href=&quot;http://www.poetryfoundation.org/poem/173902&quot;&gt;Longfellow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;^d&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Compiler introduction of transients to pure functions</title>
    <link href="https://www.arrdem.com/2014/09/17/compiler_introduction_of_transients_to_pure_functions/"/>
    <updated>2014-09-17T23:13:10+00:00</updated>
    <id>https://www.arrdem.com/2014/09/17/compiler_introduction_of_transients_to_pure_functions</id>
    <content type="html">&lt;p&gt;In Clojure and pure functinal languages, the abstraction is provided
that values cannot be updated, only new values may be
produced. Naively, this means that every update to a value must
produce a full copy of the original value featuring the desired
change. More sophisticated implementations may opt for structural
sharing, wherein updated versions of some structure share backing
memory with the original or source value on the substructures where no
update is performed. Substructures where there is an update must be
duplicated and updated as in the naive case, but for tree based
datastructures this can reduce the cost of a typical update from
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;O(N)&lt;/code&gt; on the size of the updated structure to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;O(log(N))&lt;/code&gt; because the
rest of the structure may be shared and only the “updated” subtree
needs to be duplicated.&lt;/p&gt;

&lt;p&gt;This means that tree based structures which maximize the ammount of
sharable substructure perform better in a functional context because
they minimize the fraction of a datastructure which must be duplicated
during any given update.&lt;/p&gt;

&lt;p&gt;Unfortunately however, such structural sharing still carries a
concrete cost in terms of memory overhead, garbage collection and
cache and performance when compared to a semantically equivalent
update in place over a mutable datastructure. A mutable update is
typically &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;O(1)&lt;/code&gt;, with specific exceptions for datastructures
requiring amortized analysis to achieve near &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;O(1)&lt;/code&gt; performance.&lt;/p&gt;

&lt;p&gt;Ideally, we would be able to write programs such that we preserve the
abstraction of immutable values, while enabling the compiler or other
runtime to detect when intentional updates in place are occurring and
take the opportunity to leverage the performance improvements
consequent from mutable data in these cases while ensuring that no
compiler introduced mutability can become exposed to a user through
the intentional API as built by the programmer.&lt;/p&gt;

&lt;p&gt;In such a “pure” language, there is only one class of functions,
functions from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Immutable&lt;/code&gt; values to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Immutable&lt;/code&gt; values. However if we
wish to minimize the performance overhead of this model four cases
become obvious. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;λ Immutable → Immutable&lt;/code&gt; functions are clearly
required as they represent the intentional API that a programmer may
write. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;λ Mutable → Mutable&lt;/code&gt; functions could be introduced as
implementation details within an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;λ Immutable → Immutable&lt;/code&gt; block, so
long as the API contract that no mutable objects may leak is
preserved.&lt;/p&gt;

&lt;p&gt;Consider the Clojure program&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Clojure&quot;&gt;(reduce (partial apply assoc)
    {}
    (map vector
	   (range 10000)
	   (range 10000)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This program will sequentially apply the non-transient association
operation to a value (originally the empty map) until it represents
the identity mapping over the interval [0,9999]. In the naive case,
this would produce 10,000 full single update coppies of the
map. Clojure, thanks to structural sharing, will still produce 10,000
update objects, but as Clojure’s maps are implemented as log₃₂
&lt;a href=&quot;http://en.wikipedia.org/wiki/Hash_array_mapped_trie&quot;&gt;hash array mapped tries&lt;/a&gt;,
meaning that only the array containing the “last” n % 32 key/value
pairs must be duplicated, more the root node. This reduces the cost of
the above operation from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T(~10,000²)&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T(10,000*64) ≊ T(640,000)&lt;/code&gt;
which is huge for performance. However, a
&lt;a href=&quot;http://c2.com/cgi/wiki?SufficientlySmartCompiler&quot;&gt;Sufficiently Smart Compiler&lt;/a&gt;
could recognize that the cardinality of the produced map is
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max(count(range(10000)), count(range(10000)))&lt;/code&gt;, clearly
being 10000. Consequently an array map of in the worst case 10000
elements is required given ideal hashing, however assuming a load
factor of 2/3 this means our brilliant compiler can preallocate a
hashmap of 15000 entries (presumed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T(1)&lt;/code&gt;), and then perform
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;T(10000)&lt;/code&gt; hash insertions with a very low probability of having to
perform a hash table resize due to accounting for hash distribution
and sizing the allocated table to achieve a set load factor.&lt;/p&gt;

&lt;p&gt;Clearly at least in this example the mutable hash table would be an
immense performance win because while we splurge a bit on consumed
memory due to the hash table load factor (at least compared to my
understanding of Clojure’s hash array mapped trie structure) the
brilliantly compiled program will perform no allocations which it will
not use, will perform no copying, and will generate no garbage
compared to the naive structurally shared implementation which will
produce at least 9,967 garbage pairs of 32 entry arrays.&lt;/p&gt;

&lt;p&gt;The map cardinality hack is it’s own piece of work and may or may not
be compatible with the JVM due to the fact that most structures are
not parametric on initial size and instead perform the traditional 2*n
resizing at least abstractly. However, our brilliant compiler can
deduce that the empty map which we are about to abuse can be used as a
transient and made static when it escapes the scope of the above
expression.&lt;/p&gt;

&lt;p&gt;Consider the single static assignment form for the above (assuming a
reduce definition which macroexpands into a loop) (which Clojure
doesn’t do).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	[1 ] = functionRef(clojure.core/partial)
	[2 ] = functionRef(clojure.core/apply)
	[3 ] = functionRef(clojure.core/assoc)
	[4 ] = invoke(2, 3, 4)                   ;; (partial apply assoc)
	[5 ] = {}
	[6 ] = functionRef(clojure.core/map)
	[7 ] = functionRef(clojure.core/vector)
	[8 ] = functionRef(clojure.core/range)
	[9 ] = 10000
	[10] = invoke(8, 9)                      ;; (range 10000)
	[11] = invoke(6, 7, 10, 10)              ;; (map vector [10] [10])
	[12] = functionRef(clojure.core/first)
	[13] = functionRef(clojure.core/rest)
loop:
	[14] = phi(5,  18)
	[15] = phi(11, 19)
	[16] = if(13, cont, end)
cont:
	[17] = invoke(12, 14)
	[18] = invoke(4, 14, 15)
	[19] = invoke(13, 15)
	[20] = jmp(loop)
end:
	[21] = return(18)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Where the phi function represents that the value of the phi node
depends on the source of the flow of control. Here I use the first
argument to the phi functions to mean that control “fell through” from
the preceeding block, and the second argument to mean that control was
returned to this block via instruction 20.&lt;/p&gt;

&lt;p&gt;This representation reveals the dataflow dependence between sequential
values of our victim map. We also have the contract that the return,
above labeled 21, must be of an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Immutable&lt;/code&gt; value. Consequently we can
use a trivial dataflow analysis to “push” the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Immutable&lt;/code&gt; annotation
back up the flow graph, giving us that 18, 14 and 5 must be immutable,
5 is trivially immutable, 18 depends on 14, which depends on 18 and 5,
implying that it must be immutable as well. So far so good.&lt;/p&gt;

&lt;p&gt;We can now recognize that we have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phi(Immutable, Immutable)&lt;/code&gt; on a
loop back edge, meaning that we are performing an update of some sort
within the loop body. This means that, so long as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Transient&lt;/code&gt; value is
introduced into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Immutable&lt;/code&gt; result, we can safely rewrite the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Immutable&lt;/code&gt; result to be a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Transient&lt;/code&gt;, and add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;persistent!&lt;/code&gt;
invocation before the return operation. Now we have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phi(Immutable,
Transient) → Transient&lt;/code&gt; which makes no sense, so we add a loop header
entry to make the initial empty map &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Transient&lt;/code&gt; giving us
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;phi(Transient, Transient) → Transient&lt;/code&gt; which is exactly what we
want. Now we can rewrite the loop update body to use
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;assoc! → Transient Map → Immutable Object → Immutable Object → Transient Map&lt;/code&gt;
rather than
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;assoc → Immutable Map → Immutable Object → Immutable Object → Immutable Map&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Note that I have simplified the signature of assoc to the single
key/value case for this example, and that the key and value must both
be immutable. This is required as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;persistent!&lt;/code&gt; function will
render only the target object itself and not its references
persistent.&lt;/p&gt;

&lt;p&gt;This gives us the final operation sequence&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	[1 ] = functionRef(clojure.core/partial)
	[2 ] = functionRef(clojure.core/apply)
	[3 ] = functionRef(clojure.core/assoc!)
	[4 ] = invoke(2, 3, 4)                      ;; (partial apply assoc)
	[5 ] = functionRef(clojure.core/transient!)
	[6 ] = {}
	[7 ] = invoke(5, 6)
	[8 ] = functionRef(clojure.core/map)
	[9 ] = functionRef(clojure.core/vector)
	[10] = functionRef(clojure.core/range)
	[11] = 10000
	[12] = invoke(10, 11)                       ;; (range 10000)
	[13] = invoke(8, 9, 12, 12)                 ;; (map vector [12] [12])
	[14] = functionRef(clojure.core/first)
	[15] = functionRef(clojure.core/rest)
loop:
	[16] = phi(7,  20)
	[17] = phi(13, 21)
	[18] = if(17, cont, end)
cont:
	[19] = invoke(14, 17)
	[20] = invoke(4, 16, 17)
	[21] = invoke(15, 17)
	[22] = jmp(loop)
end:
    [23] = functionRef(clojure.core/persistent!)
	[24] = invoke(23, 20)
	[25] = return(24)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Having performed this rewrite we’ve one. This transform allows an
arbitrary loop using a one or more persistent datastructures a
accumulators to be rewritten in terms of transients if there exists
(or can be inferred) a matching &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Transient t → Transient t&lt;/code&gt; updater
equivalent to the updater used. Note that if a non-standard library
updater (say a composite updater) is used, then the updater needs to
be duplicated and if possible recursively rewritten from a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Persistent
t → Persistent t&lt;/code&gt; by replacing the standard library operations for
which there are known doubles with their &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Transient t&lt;/code&gt; counterparts
until either the rewrite fails to produce a matching &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Transient t →
Transient t&lt;/code&gt; or succeeds. If any such rewrite fails then this entire
transform must fail. Also note that this transformation can be applied
to subterms… so as long as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Persistent t&lt;/code&gt; contract is not
violated on the keys and values here of the map in a nontrivial
example their computation as well could be rewritten to use compiler
persisted transients.&lt;/p&gt;

&lt;p&gt;Now yes you could have just written&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Clojure&quot;&gt;(into {}
   (map vector
      (range 10000)
	  (range 10000)))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which would have used transients implicitly, but that requires that
the programmer manually perform an optimization requiring further
knowledge of the language and its implementation details when clearly
a relatively simple transformation would not only reveal the potential
for this rewrite but would provide it in the general case of
arbitrarily many mutable accumulators rather than into’s special case
of just one.&lt;/p&gt;

&lt;p&gt;^d&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>On Future Languages</title>
    <link href="https://www.arrdem.com/2014/08/26/on_future_languages/"/>
    <updated>2014-08-26T05:05:56+00:00</updated>
    <id>https://www.arrdem.com/2014/08/26/on_future_languages</id>
    <content type="html">&lt;p&gt;As &lt;a href=&quot;https://twitter.com/extempore2&quot;&gt;Paul Philips&lt;/a&gt; notes at the end of
his talk
&lt;a href=&quot;https://www.youtube.com/watch?v=TS1lpKBMkgg&quot;&gt;We’re Doing It All Wrong [2013]&lt;/a&gt;,
ultimately a programming language is incidental to building software
rather than critical. Ultimately the “software developer” industry is
not paid to write microcode. Rather, software as an industry exists to
deliver buisness solutions. Similarly computers themselves are by a
large incidental. Rather, they are agents for delivering data
warehousing, search and transmission solutions. Very few people are
employed to improve software and computer technology for the sake of
doing so compared to the hordes of industry programmers who ultimately
seek to use computers as a magic loom to create value for a
business. In this light I think it’s meaningful to investigate recent
trends in programming languages and software design as they pertain to
solving problems not to writing code.&lt;/p&gt;

&lt;p&gt;As the last four or five decades of writing software stand witness,
software development is rarely an exercise in first constructing a
perfect program, subsequently delivering it and watching pleased as a
client makes productive use of it until the heat death of the
universe. Rather, we see that software solutions when delivered are
discovered to have flaws, or didn’t solve the same problem that the
client thought that it would solve, or just didn’t do it quite right,
or the problem changed. All of these changes to the environment in
which the software exists demand changes to the software itself.&lt;/p&gt;

&lt;h2 id=&quot;malleability&quot;&gt;Malleability&lt;/h2&gt;

&lt;p&gt;In the past, we have attempted to develop software as if we were going
to deploy perfect products forged of pure adamantium which will endure
forever unchanged. This begot the entire field of software
architecture and the top down school of software design. The issue
with this model as the history of top down software engineering stands
testament is that business requirements change if they are known, and
must be discovered and quantified if they are unknown. This is an old
problem
&lt;a href=&quot;http://users.ece.utexas.edu/~perry/education/SE-Intro/fakeit.pdf&quot;&gt;with no good solution&lt;/a&gt;.
In the face of incomplete and/or changing requirements all that can be
done is to evolve software as rapidly and efficiently as possible to
meet changes as Parnas argues.&lt;/p&gt;

&lt;p&gt;In the context of &lt;em&gt;expecting&lt;/em&gt; change, languages and the other tools
used to develop changing software must be efficient to re-architect
and change. As Paul Philips says in the above talk,
&lt;a href=&quot;https://www.youtube.com/watch?feature=player_detailpage&amp;amp;v=TS1lpKBMkgg#t=307&quot;&gt;“modification is undesirable, modifiability is paramount”&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Looking at languages which seem to have enjoyed traction in my
lifetime, the trend seems to have been that, with the exception of
tasks for which the language in which the solution was to be built was
a requirement the pendulum both of language design and of language use
has been swinging away from statically compiled languages like Java, C
&amp;amp; C++ (the Algol family) towards interpreted languages (Perl, Python,
Ruby, Javascript) which trade off some performance for interactive
development and immediacy of feedback.&lt;/p&gt;

&lt;p&gt;Today, that trend would seem to be swinging the other way. Scala, a
statically checked language base around extensive type inference with
some interactive development support has been making headway. Java and
C++ seem to have stagnated but are by no means dead and gone. Google
Go, Mozilla Rust, Apple Swift and others have appeared on the scene
also fitting into this intermediary range between interactive and
statically compiled with varying styles of type inference to achieve
static typing while reducing programmer load. Meanwhile the hot
frontier in language research seems to be static typing and type
inference as the liveliness of the Haskell ecosystem is ample proof.&lt;/p&gt;

&lt;p&gt;Just looking at these two trends, I think it’s reasonable to draw the
conclusion that interpreted, dynamically checked, dynamically
dispatched languages like Python and Ruby succeeded at providing more
malleable programming environments than the languages which came
before them (the Algol family &amp;amp; co). However while making changes in a
dynamically checked language is well supported, maintaining
correctness is difficult because there is no compiler or type checker
to warn you that you’ve broken something. This limits the utility of
malleable environments, because software which crashes or gives
garbage results is of no value compared to software which behaves
correctly. However, as previously argued, software is not some work of
divine inspiration which springs fully formed from the mind onto the
screen. Rather the development of software is an evolutionary
undertaking involving revision (which is well suited to static type
checking) and discovery which may not be.&lt;/p&gt;

&lt;p&gt;As a checked program must always be in a legal (correct with respect
to the type system) state by definition, this precludes some elements
of development by trial and error as the type system will ultimately
constrain the flexibility of the program requiring systematic
restructuring where isolated change could have sufficed. This is not
argued to be a flaw, it is simply a trade off which I note between
allowing users to express and experiment with globally “silly” or
“erroneous” constructs and the strict requirement that all programs be
well formed and typed when with respect to some context or the
programmer’s intent the program may in fact be well formed.&lt;/p&gt;

&lt;p&gt;As program correctness is an interesting property, and one which
static model checking including “type systems” is well suited to
assisting with, I do not mean to discount typed languages. Ultimately,
a correct program must be well typed with respect to some type system
whether that system is formalized or not.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Program testing can be used to show the presence of bugs, but never
to show their absence!&lt;/p&gt;

  &lt;p&gt;~ Dijkstra (1970)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Static model checking on the other hand, can prove the presence of
flaws with respect to some system. This property alone makes static
model checking an indispensable part of software assurance as it
cannot be replaced by any other non-proof based methodology such as
assertion contracts or test cases.&lt;/p&gt;

&lt;p&gt;Given this apparent trade off between flexibility and correctness,
Typed Racket, Typed Clojure and the recent efforts at Typed Python are
interesting, because they provide halfway houses between the “wild
west” of dynamic dispatch &amp;amp; dynamic checking languages like
traditional Python, Ruby and Perl and the eminently valuable model
checking of statically typed languages. This is because they enable
programmers to evolve a dynamically checked system, passing through
states of varying levels of soundness towards a better system and then
once it has reached a point of stability solidify it with static
typing, property based testing and other static reasoning techniques
without translating programs to another language which features
stronger static analysis properties.&lt;/p&gt;

&lt;h2 id=&quot;utility--rapidity-from-library-support&quot;&gt;Utility &amp;amp; Rapidity from Library Support&lt;/h2&gt;

&lt;p&gt;Related to malleability in terms of ultimately delivering a solution
to a problem that gets you paid is the ability to get something done
in the first place. Gone (forever I expect) are the days when programs
are built without using external libraries. Looking at recent
languages, package/artifact management and tooling capable of
trivializing leveraging open source software has EXPLODED. Java has
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mvn&lt;/code&gt;, Python has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pip&lt;/code&gt;, Ruby has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem&lt;/code&gt;, Haskell has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cabal&lt;/code&gt;, Node has
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt; and the Mozilla Rust team deemed a package manager so critical
to the long term success of the language that they built their &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cargo&lt;/code&gt;
system long before the first official release or even release
candidate of the language.&lt;/p&gt;

&lt;p&gt;Why are package managers and library infrastructure critical? Because
they enable massive code reuse, &lt;em&gt;especially of vendor code&lt;/em&gt;. Building
a webapp? Need a datastore? The investment of buying into any
proprietary database you may choose has been driven so low by the ease
with which $free (and sometimes even free as in freedom) official
drivers can be found and slotted into place it’s silly. The same goes
for less vendor specific code… regex libraries, logic engine
libraries, graphics libraries and many more exist in previously
undreamed of abundance (for better or worse) today.&lt;/p&gt;

&lt;p&gt;The XKCD &lt;a href=&quot;http://gkoberger.github.io/stacksort/&quot;&gt;stacksort&lt;/a&gt; algorithm
is a tongue in cheek reference to the sheer volume of free as in
freedom forget free as in beer code which can be found and leveraged
in developing software today.&lt;/p&gt;

&lt;p&gt;This doesn’t just go for “library” support, I’ll also include here FFI
support. Java, the JVM family of languages, Haskell, Ocaml and many
others gain much broader applicability for having FFI interfaces for
leveraging the decades of C and C++ libraries which predate
them. Similarly Clojure, Scala and the other “modern” crop of JVM
languages gain huge utility and library improvements from being able
to reach through to Java and leverage the entire Java ecosystem
selectively when appropriate.&lt;/p&gt;

&lt;p&gt;While it’s arguably unfair to compare languages on the basis of the
quantity of libraries available as this metric neglects functionally
immeasurable quality and utility, the presence of &lt;em&gt;any&lt;/em&gt; libraries is a
legitimate comparison in terms of potential productivity to
comparative absence.&lt;/p&gt;

&lt;p&gt;What good is a general purpose building material, capable of
constructing any manner of machine, when simple machines such as the
wheel or the ramp must be reconstructed by every programmer? Not
nearly so much utility as a building material providing these things
on a reusable basis at little or no effort to the builder regardless
of the ease with which one may custom build such tools as needed.&lt;/p&gt;

&lt;h2 id=&quot;so-whats-the-big-deal&quot;&gt;So What’s the Big Deal&lt;/h2&gt;

&lt;p&gt;I look at this and expect to see two trends coming out of it. The
first of which is that languages with limited interoperability and/or
limited library bases are dead. Stone cold dead. Scheme, RⁿRS, and
Common Lisp were my introductions to the Lisp family of
languages. They are arguably elegant and powerful tools, however
compared to other tools such as python they seem offer at best equal
leverage due to prevailing lack of user let alone newbie friendly
library support compared to other available languages.&lt;/p&gt;

&lt;p&gt;I have personally written 32KLoC in Clojure. More counting
intermediary diffs. That I can find on my laptop. Why? Because Clojure
unlike my experiences with Common Lisp and Scheme escapes the
proverbial
&lt;a href=&quot;http://www.winestockwebdesign.com/Essays/Lisp_Curse.html&quot;&gt;lisp curse&lt;/a&gt;
simply thanks to tooling which facilitates library and infrastructure
sharing at a lower cost than the cost of reinvention. Reinvention
still occurs, as it always will, but the marginal cost of improving an
existing tool vs writing a new one is in my experience a compelling
motivator for maintaining existing tool kits and software. This means
that Clojure at least seems to have broken free of the black hole of
perpetual reinvention and is consequently liberating to attack &lt;em&gt;real&lt;/em&gt;
application critical problems rather than distracting programmers into
fighting simply to build a suitable environment.&lt;/p&gt;

&lt;p&gt;It’s not that Clojure is somehow a better language, arguably it
ultimately isn’t since it lacks the inbuilt facilities for many
interesting static proof techniques, but that’s not the point. As
argued above, the language(s) we use are ultimately incidental to the
task of building a solution to some problem. What I really want is
leverage from libraries, flexibility in development, optional and/or
incremental type systems and good tooling. At this task, Clojure seems
to be a superior language.&lt;/p&gt;

&lt;h2 id=&quot;the-long-view&quot;&gt;The Long View&lt;/h2&gt;

&lt;p&gt;This is not all to say that I think writing languages is pointless,
nor that the languages we have today are the best we’ve ever had let
alone the best we ever will have at simultaneously providing utility,
malleability and safety. Nor is this to say that we’ll be on the JVM
forever due to the value of legacy libraries or something equally
silly. This is however to say that I look with doubt upon language
projects which do not have the benefit of support from a “major
player”, a research entity or some other group willing to fund long
term development in spite of short term futility simply because the
literal price of bootstrapping a “new” language into a state of
compelling utility is expensive in terms of man-years.&lt;/p&gt;

&lt;p&gt;This conclusion is, arguably, my biggest stumbling block with my
&lt;a href=&quot;http://github.com/oxlang/oxlang&quot;&gt;Oxlang&lt;/a&gt; project. It’s not that the
idea of the language is bad, it’s that a tradeoff must be carefully
made between novelty and utility. Change too much and Oxlang will be
isolated from the rest of the Clojure ecosystem and will loose hugely
in terms of libraries as a result. Change to little and it won’t be
interesting compared to Clojure. Go far enough, and it will cross the
borders of hard static typing, entering the land of Shen, Ocaml and
Haskell and as argued above I think sacrifice interesting flexibility
for uncertain gains.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Of Oxen, Carts and Ordering</title>
    <link href="https://www.arrdem.com/2014/08/06/of_oxen,_carts_and_ordering/"/>
    <updated>2014-08-06T01:40:32+00:00</updated>
    <id>https://www.arrdem.com/2014/08/06/of_oxen,_carts_and_ordering</id>
    <content type="html">&lt;p&gt;Well, the end of
&lt;a href=&quot;https://developers.google.com/open-source/soc/?csw=1&quot;&gt;Google Summer of Code&lt;/a&gt;
is in sight and it’s long past time for me to make a report on the
state of my Oxcart Clojure compiler
project. &lt;a href=&quot;/2014/06/26/oxcart_and_clojure/&quot;&gt;When last I wrote about it&lt;/a&gt;,
Oxcart was an analysis suite and a work proposal for an emitter.&lt;/p&gt;

&lt;p&gt;To recap the previous post: Clojure uses Var objects, an atomic,
threadsafe reference type with support for naming and namespace
binding semantics to create a literal global hashmap from symbols to
binding vars, with a literal stack of thread local bindings. These
vars form the fundamental indirection mechanism by which Clojure
programs map from textual symbols to runtime functions. Being
atomically mutable, they also serve to enable dynamic re-binding and
consequently enable REPL driven development.&lt;/p&gt;

&lt;p&gt;But for this second aspect of providing for dynamic redefinition of
symbols, Clojure could be statically compiled eliminating var
indirection and achieving a performance improvement.&lt;/p&gt;

&lt;p&gt;Moreover, in the style of Clojurescript, exposing the full source of
the language to an agressive static compiler could yield total program
size improvements in comparison to programs running on the official
Clojure compiler/runtime pair.&lt;/p&gt;

&lt;p&gt;So. This was the premise upon which my Project Oxcart GSoC began. Now,
standing near the end of GSoC what all has happened, where does the
project stand and what do I consider results?&lt;/p&gt;

&lt;p&gt;As of this post’s writing,
&lt;a href=&quot;https://github.com/arrdem/oxcart/commit/e7a22a091cfb7188280c89f7d185aec10bdba6cd&quot;&gt;e7a22a09&lt;/a&gt;
is the current state of the Oxcart project. The Oxcart loader and
analyzer, built atop Nicola Mometto’s tools.analyzer.jvm and
tools.emitter.jvm, is capable of loading and generating a whole
program AST for arbitrary Clojure progrms. The various passes in the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oxcart.passes&lt;/code&gt; subsystem implement a variety of per-form and whole
program traversals including λ lifting, use analysis, reach analysis
and taken as value analysis. There is also some work on a multiple
arity function reduction system, but that seems to be a problem module
at present. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oxcart.emitter&lt;/code&gt; subsystem currently features two
emitters, only one of which I can claim is of my
authoring. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oxcart.emitter.clj&lt;/code&gt; is a function from an Oxcart whole
program AST to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(do)&lt;/code&gt; form containing source code for the entire
program as loaded. This has primarily been a tool for debugging and
ensuring the sanity of various program transformations.&lt;/p&gt;

&lt;p&gt;The meat of Oxcart is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oxcart.emitter.jvm&lt;/code&gt;, a wrapper around a
modified version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.tools.jvm.emit&lt;/code&gt; which features changes
for emitting statically specialized bytecode which doesn’t make use of
var indirection. These changes are new, untested and subject to change
but they seem to work. As evidenced by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bench-vars.sh&lt;/code&gt; script in
the Oxcart project’s root directory, for some programs the static
target linking transform done by Oxcart can achieve a 24% speedup.&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
Times in ms.
Running Clojure 1.6.0 compiled test.vars....
1603.894357
1369.60414
1348.747718
1345.55669
1343.380462
1341.73058
1346.342237
1345.655224
1395.983262
1340.063011
1339.7823
1399.282023
1451.58462
1353.231654
1348.458151
Oxcart compiling test.vars....
Running Oxcart compiled test.vars....
1256.391888
1066.860551
1033.764971
1031.380052
1032.09911
1030.032666
1040.505754
1040.419533
1041.749353
1040.038301
1041.699772
1044.441135
1095.809551
1072.494466
1047.65782
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;How/why is this possible? The benchmark above is highly artificial in
that it takes 500 defs, and tests over several thousand iterations of
selectively executing half of them at random. This benchmark is
designed to exaggerate the runtime cost of var indirection by being
inefficient to inline and making great use of the (comparatively)
expensive var dereference operation.&lt;/p&gt;

&lt;p&gt;So what does this mean for Clojure? Is Oxcart proof that we can and
should build a faster Clojure implementation or is there a grander
result here we should consider?&lt;/p&gt;

&lt;p&gt;Clojure’s existing compiler operates on a “good enough” principle.
It’s not especially nice to read nor especially intelligent, but it
manages to produce reasonably efficient bytecode. The most important
detail of the reference Clojure compiler is that it operates on a form
by form basis and is designed to do so. This is an often forgotten
detail of Clojure, and one which this project has made me come to
appreciate a lot more.&lt;/p&gt;

&lt;p&gt;When is static compilation appropriate and valuable? Compilation is
fundamentally an analysis and specialization operation designed to
make a trade off between “start” or “compile” time and complexity and
runtime performance. This suggests that in different contexts
different trade offs may be appropriate. Furthermore, static
compilation tends to inhibit program change. To take the extreme
example of say C code which is directly linked change in a single
function, if a single function increases in bytecode size so that it
cannot be updated in place. In this case all code which makes use of
it (worst case the rest of the program) must be rewritten to reflect
the changed location of the changed function. While it is possible to
build selective recompilation systems which can do intelligent and
selective rebuilding (GHCI being an example of this), achieving full
compilation performance at interactive development time is simply a
waste of time on compilation when the goal of REPL driven development
is to provide rapid feedback and enable exploration driven development
and problem solving.&lt;/p&gt;

&lt;p&gt;While vars are clearly inefficient from a perspective of minimizing
function call costs, they are arguably optimal in terms of enabling
this development style. Consider the change impact of altering a
single definition on a Clojure instance using var indirection rather
than static linking. There’s no need to compute, recompile and reload
the subset of your program impacted by this single change. Rather the
single changed form is recomputed, and the var(s) bound by the
recompiled expression are altered. In doing so, no changes need be
made to the live state of the rest of the program. When next client
code is invoked the JVM’s fast path if any will be invalidated as the
call target has changed, but this is handled silently by the runtime
rather than being a language implementation detail. Furthermore var
indirection means that compiling an arbitrary Clojure form is
trivial. After handling all form local bindings (let forms and
soforth), try to resolve the remaining expressions to vars in the
mapped namespace, and to a class if no var is found. Brain dead even,
but sufficient and highly effective in spite of its lack of
sophistication.&lt;/p&gt;

&lt;p&gt;While, as Oxcart is proof, it is possible to build a static compiler
for some subset of Clojure, doing so produces not a static Clojure but
a different language entirely because so much of the Clojure ecosystem
and standard library even are defined in terms of dynamic
redefinition, rebinding and dispatch. Consider for instance the
multimethod system, often lauded with the claim that multimethod code
is user extensible. Inspecting the macorexpand of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;defmethod&lt;/code&gt; form
you discover that its implementation far from being declarative is
based on altering the root binding of the multimethod to install a new
dispatch value. While it would be possible to statically compile this
“feature” by simply collecting all defmethods over each multimethod
and AOT computing the final dispatch table, however this is semantics
breaking as it is strictly legal in Clojure to dynamically define
additional multimethod entries just as it is legal to have an
arbitrary do block containing defs.&lt;/p&gt;

&lt;p&gt;So, in short, by trying to do serious static compilation you largely
sacrifice REPL development and to do static compilation of Clojure you
wind up defining another language which is declarative on defs,
namespaces and dependencies rather than imperative as Clojure is. I
happen to think that such a near-Clojure static language, call it
Clojurescript on the JVM, would be very interesting and valuable but
Clojure as implemented currently on the JVM is no such thing. This
leads me to the relatively inescapable conclusion that building a
static compiler for Clojure is putting the cart before the ox since
the language simply was not designed to benefit from it.&lt;/p&gt;

&lt;h3 id=&quot;moving-forwards&quot;&gt;Moving Forwards&lt;/h3&gt;

&lt;p&gt;Now. Does this mean we should write off tools.emitter.jvm, Clojure in
Clojure and Oxcart? By no means. tools.emitter.jvm uses the same var
binding structure and function interface that Clojure does. Moreover
it’s a much nicer and more flexible single form level compiler that I
happen to think represents a viable and more transparent replacement
for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.lang.Compiler&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So what’s that leave on the table? Open question. Clojure’s compiler
has only taken major changes from two men: Rich and Stu. While there
is merit in considered design and stability, this also means that
effort towards cleaning up the core of Clojure itself and not directed
at a hard fork or redesign of Clojure is probably wasted especially in
the compiler.&lt;/p&gt;

&lt;p&gt;Clearly while var elimination was a successful optimization due to the
value Clojure derives from the Var system it’s not a generally
applicable one. However it looks like Rich has dug the old
invokeStatic code back out for Clojure 1.7 and the grapevine is making
10% noises, which is on par with what Oxcart seems to get for more
reasonable inputs so we’ll see where that goes.&lt;/p&gt;

&lt;p&gt;While immutable datastructures are an awesome abstraction, Intel, AMD
and ARM have gotten very good at building machines capable of
exploiting program locality for performance and this property is
fundamentally incompatible with literal immutability. Transients can
help mitigate Clojure’s memory woes, and compiler introduction of
transients to improve memory performance could be
interesting. Unfortunately again this is a whole program optimization
which clashes with the previous statement of the power that Clojure
derives from single form compilation.&lt;/p&gt;

&lt;p&gt;Using core.typed to push type signatures down to the bytecode level
would be interesting, except that since almost everything in Clojure
is a boxed object and object checkcasts are cheap and this would
probably result in little performance improvement unless the core
datatypes were reworked to be type parametric. Also another whole
program level transform requiring an Oxcart style whole program
analysis system.&lt;/p&gt;

&lt;p&gt;The most likely avenue of work is that I’ll start playing with a
partial fork of Clojure which disassociates RT from the compiler,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data_readers.clj&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user.clj&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure/core.clj&lt;/code&gt;. While this will
render Oxcart even more incompatible with core Clojure, it will also
free Oxcart to emit Clojure.core as if it were any other normal
Clojure code including tree shaking and escape the load time overhead
of bootstrapping Clojure core entirely.&lt;/p&gt;

&lt;p&gt;This coming Monday I’ll be giving a talk on Oxcart at the Austin TX
Clojure meetup, so there’s definitely still more to come here
regardless of the Clojure/Conj 14 accepted talk results.&lt;/p&gt;

&lt;p&gt;^D&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Of Mages and Grimoires</title>
    <link href="https://www.arrdem.com/2014/07/12/of_mages_and_grimoires/"/>
    <updated>2014-07-12T04:43:40+00:00</updated>
    <id>https://www.arrdem.com/2014/07/12/of_mages_and_grimoires</id>
    <content type="html">&lt;p&gt;When I first got started with Clojure, I didn’t know (and it was a
while before I was told) about the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.repl&lt;/code&gt; toolkit which offers
Clojure documentation access from within an nREPL instance. Coming
from the Python community I assumed that Clojure, like Python, has
excellent API documentation with examples that a total n00b like
myself could leverage to bootstrap my way into simple competence.&lt;/p&gt;

&lt;p&gt;While Clojure does indeed have web documentation hosted on GitHub’s
Pages service, they are eclipsed in Google PageRank score if not in
quality as well by a community built site owned by Zachary Kim:
&lt;a href=&quot;http://Clojuredocs.org&quot;&gt;ClojureDocs&lt;/a&gt;. This wouldn’t be a real problem
at all, were it not for the fact that ClojureDocs was last updated
when Clojure 1.3 was released. In 2011.&lt;/p&gt;

&lt;p&gt;While Clojure’s core documentation and core toolkits haven’t changed
much since the 1.3 removal of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.contrib.*&lt;/code&gt;, I have recently
felt frustrated that newer features of Clojure such as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;as-&amp;gt;&lt;/code&gt;, and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cond-&amp;gt;&amp;gt;&lt;/code&gt; which I find very useful in my day to day Clojure hacking
not only were impossible to search for on Google (being made of
characters Google tends to ignore) but also didn’t have ClojureDocs
pages due to being additions since 1.3. Long story short: I finally
got hacked off enough to yak shave my own alternative.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;**drumroll**&lt;/b&gt;&lt;/p&gt;

&lt;center mardown=&quot;1&quot;&gt;
[Grimoire](http://conj.io/)
&lt;/center&gt;

&lt;h2 id=&quot;mission&quot;&gt;Mission&lt;/h2&gt;

&lt;p&gt;Grimoire seeks to do what ClojureDocs did, being provide community
examples of Clojure’s core functions along with their source code and
official documentation. However with Grimoire I hope to go farther
than ClojureDocs did in a number of ways.&lt;/p&gt;

&lt;p&gt;I would like to explore how I find and choose the functions I need,
and try to optimize accessing Grimoire accordingly so that I can find
the right spanner as quickly as possible. Part of this effort is the
recent introduction of a modified Clojure Cheat Sheet (thanks to Andy
Fingerhut &amp;amp; contributors) as Grimoire’s primary index.&lt;/p&gt;

&lt;p&gt;Something else I would like to explore with Grimoire is automated
analysis and link generation between examples. In ClojureDocs, (and I
admit Grimoire as it stands) examples were static text analyzed for
syntax before display to users. As part of my work on Oxcart, I had an
idea for how to build a line information table from symbols to binding
locations and I’d like to explore providing examples with inline links
to the documentation of other functions used.&lt;/p&gt;

&lt;p&gt;Finally I’d like to go beyond Clojure’s documentation. ClojureDocs and
Grimoire at present only present the official documentation of Clojure
functions. However some of Clojure’s behavior such as the type
hierarchy is not always obvious.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&amp;lt; amalloy&amp;gt; ~colls&lt;/p&gt;

  &lt;p&gt;&amp;lt; Clojurebot&amp;gt; colls is &lt;a href=&quot;http://www.brainonfire.net/files/seqs-and-colls/main.html&quot;&gt;http://www.brainonfire.net/files/seqs-and-colls/main.html&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Frankly the choice of the word Grimoire is a nod in this
direction… a joke as it were on
&lt;a href=&quot;http://dota2.gamepedia.com/Invoker#Bio&quot;&gt;Invoker’s&lt;/a&gt; fluff and the
Archmagus like mastery which I see routinely exhibited on Freenode’s
Clojure channel of the many ins and outs of the language while I
struggle with basic stuff like “Why don’t we have
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core/atom?&lt;/code&gt;” and “why is a Vector not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;seq?&lt;/code&gt; when it is
Sequable and routinely used as such?”. “Why don’t we have
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core/sequable?&lt;/code&gt;”?&lt;/p&gt;

&lt;p&gt;Clojure’s core documentation doesn’t feature type signatures, even
types against Clojure’s data interfaces. I personally find that I
think to a large degree in terms of the types and structure of what
I’m manipulating I find this burdensome. Many docstrings are simply
wanting if even present. I think these are usability defects and would
like to explore augmenting the “official” Clojure
documentation. &lt;a href=&quot;https://github.com/jafingerhut/thalia&quot;&gt;Andy Fingerhut’s thalia&lt;/a&gt;
is another effort in this direction and one which I hope to explore
integrating into Grimoire as non-invasively as possible.&lt;/p&gt;

&lt;h2 id=&quot;status&quot;&gt;Status&lt;/h2&gt;

&lt;p&gt;Much of what I have talked about here is work that needs to be
done. The first version of Grimoire that I announced originally on the
Clojure mailing list was a trivial hierarchical directory structure
aimed at users who sorta kinda knew what they were looking for and
where to find it because that’s all I personally need out of a
documentation tool for the most part after two years of non-stop
Clojure. Since then I’ve been delighted to welcome and incorporate
criticism and changes from those who have found Grimoire similarly of
day to day use, however I think it’s important to note that Grimoire
is fundamentally user land tooling as is Leiningen and as is Thalia.&lt;/p&gt;

&lt;p&gt;As such, I don’t expect that Grimoire will ever have any official
truck with Rich’s sanctioned documentation. This and the hope that we
may one day get better official docs mean that I don’t really foresee
migrating Grimoire off of my personal hosting to a more “Clojure-ey”
domain. Doing so would lend Grimoire an undue level of
“official-ness”, forget the fact that I’m now rather attached to the
name and that my browser goes to the right page with four keystrokes.&lt;/p&gt;

&lt;h2 id=&quot;future&quot;&gt;Future&lt;/h2&gt;

&lt;p&gt;As far as I am concerned, Grimoire is in a good place. It’s under my
control, I have shall we say a side project as I’m chugging along on
“day job” for GSoC and it seems judging by Google Analytics that some
300 other Clojureists have at least bothered to stop by and some 70
have found Grimoire useful enough to come back for more all in the
three days that I’ve had analytics on. There is still basic UI work to
be done, which isn’t surprising because I claim no skill or taste as a
graphic designer, and there’s a lot of stuff I’d like to do in terms
of improving upon the existing documentation.&lt;/p&gt;

&lt;p&gt;Frankly I think it’s pretty crazy that I put about 20 hours of effort
into something, threw it up on the internet and suddenly for the first
time in my life I have honest to god &lt;em&gt;users&lt;/em&gt;. From 38 countries. I
should try this “front end” stuff more often.&lt;/p&gt;

&lt;p&gt;So here’s hoping that Grimoire continues to grow, that other people
find it useful, and that I manage to accomplish at least some of the
above. While working on Oxcart. And summer classes. Yeah…..&lt;/p&gt;

&lt;p&gt;^D&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Oxcart and Clojure</title>
    <link href="https://www.arrdem.com/2014/06/26/oxcart_and_clojure/"/>
    <updated>2014-06-26T20:18:45+00:00</updated>
    <id>https://www.arrdem.com/2014/06/26/oxcart_and_clojure</id>
    <content type="html">&lt;p&gt;Well, it’s a month into
&lt;a href=&quot;https://www.google-melange.com/&quot;&gt;Google Summer of Code&lt;/a&gt;, and I still
haven’t actually written anything about
&lt;a href=&quot;https://www.google-melange.com/gsoc/project/details/google/gsoc2014/arrdem/5676830073815040&quot;&gt;my project&lt;/a&gt;,
better known as &lt;a href=&quot;https://github.com/arrdem/oxcart&quot;&gt;Oxcart&lt;/a&gt; beyond what
little per function documentation I have written for Oxcart and the
&lt;a href=&quot;http://us4.campaign-archive1.com/?u=a33b5228d1b5bf2e0c68a83f4&amp;amp;id=6ee36652d6&quot;&gt;interview I did with Eric N.&lt;/a&gt;. So
it’s time to fix that.&lt;/p&gt;

&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;/h2&gt;

&lt;p&gt;Clojure isn’t “fast”, it’s simply “fast enough”. Rich, while really
smart guy with awesome ideas isn’t a compilers research team and
didn’t design Clojure with a laundry list of tricks that he wanted to
be able to play in the compiler in mind. Instead in the beginning,
Rich designed a language that he wanted to use to do work, built a
naive compiler for it, confirmed that JVM JITs could run the resulting
code sufficiently fast, and got on with actually building things.&lt;/p&gt;

&lt;p&gt;The consequent of Rich’s priorities is that Clojure code is in fact
fast enough to do just about whatever you want, but it could be
faster. Clojure is often criticized for its slow startup time and its
large memory footprint. Most of this footprint is not so much a
consequent of fundamental limitations of Clojure as a language (some
of it is but that’s for another time) as it is a consequent of how the
existing Clojure compiler runtime pair operate together.&lt;/p&gt;

&lt;p&gt;So Clojure wasn’t designed to have a sophisticated compiler, it
doesn’t have such a compiler, and for some applications Clojure is
slow compared to other equivalent languages as a result of not having
these things. So for GSoC I proposed to build a prototype compiler
which would attempt to build Clojure binaries tuned for performance
and I got accepted.&lt;/p&gt;

&lt;h2 id=&quot;validating-complaints&quot;&gt;Validating complaints&lt;/h2&gt;

&lt;p&gt;Okay, so I’ve made grand claims about the performance of Clojure, that
it could be faster and soforth. What exactly do I find so distasteful
in the language implementation?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vars&lt;/strong&gt; are the first and primary whipping boy. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vars&lt;/code&gt;,
&lt;a href=&quot;https://github.com/Clojure/Clojure/blob/master/src/jvm/Clojure/lang/Var.java&quot;&gt;defined over here&lt;/a&gt;,
are data structures which Clojure uses to represent bindings between
symbols and values. These bindings, even when static at compile time,
are interred at runtime in a thread shared global bindings table, and
then thread local bindings tables contain “local” bindings which take
precedence over global bindings. This is why
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(Clojure.core/alter-var-root!)&lt;/code&gt; and the other var manipulation
functions in the Clojure standard library have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-!&lt;/code&gt; postfix used
to annotate transactional memory mutation, because only a transaction
can modify the root bindings of a thread shared and thread safe &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;s are awesome because they are thread shared. This means that
if you drop a REPL in a live program you can start re-defining &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;s
willy nilly and your program will “magically” update. Why does this
work? Because Clojure programs never hold a reference to a “function”,
instead they hold a thread synchronized var which names a function and
get the latest function named by the var every time they have to call
that function.&lt;/p&gt;

&lt;p&gt;This is great because it enables the REPL driven development and
debugging pattern upon which many people rely, however for the
overwhelming majority of applications the final production form of a
program will never redefine a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;. This means that consequently the
nontrivial overhead of performing thread synchronization, fetching the
function named by a var, checking that the fn is in fact
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.lang.IFn&lt;/code&gt; and then calling the function is wasted overhead
that the reference Clojure implementation incurs every single function
call. The worst part about this is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;
&lt;a href=&quot;https://github.com/Clojure/Clojure/blob/master/src/jvm/Clojure/lang/Var.java#L22&quot;&gt;has a volatile root&lt;/a&gt;
which poisons the JVM’s HotSpot JIT by providing a break point at
function boundaries which the JIT can’t inline or analyze across.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IFn&lt;/strong&gt; is another messy part of Clojure programs. The JVM does not
have semantics for representing a pointer to a “function”. The result
is that Clojure doesn’t really have “functions” when compiled to JVM
bytecode, instead Clojure has classes providing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.invoke()&lt;/code&gt; methods
and instances of those classes, or more often &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;s naming &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IFn&lt;/code&gt;s may
be passed around as values. This isn’t a bad thing for the most part,
except that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IFn&lt;/code&gt;s use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;s to implement their &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.invoke()&lt;/code&gt; methods
and vars are slow.&lt;/p&gt;

&lt;p&gt;The real reason that this can be an issue is why do we need an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IFn&lt;/code&gt;
with multiple invoke methods? Because in Clojure functions can have
multiple arities, and the single instance of an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IFn&lt;/code&gt; could be invoked
multiple ways where a JVM Method cannot be.&lt;/p&gt;

&lt;p&gt;The real issue with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IFn&lt;/code&gt;s is that they exist at all. Every single
class referenced by a JVM program must be read from disk, verified,
loaded and compiled. This means that there is a load time cost to each
individual class in a program. Clojure exacerbates this cost by not
only generating a lot of small classes to implement &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IFn&lt;/code&gt;s. When a
namespace is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require&lt;/code&gt;d or otherwise &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;load&lt;/code&gt;ed by a compiled Clojure
program, the Clojure runtime loads &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foo__init.class&lt;/code&gt;, which creates
instances of every &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IFn&lt;/code&gt; used to back a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt; in the namespace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foo&lt;/code&gt;
and installs those definitions in the global var name table. Note that
this loading is single threaded, so all synchronization at load time
is wasteful. Also note that if there are top level forms like
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(println &quot;I got loaded!&quot;)&lt;/code&gt; in a Clojure program those are evaluated
when the namespace containing the form is loaded.&lt;/p&gt;

&lt;h2 id=&quot;the-sales-pitch&quot;&gt;The sales pitch&lt;/h2&gt;

&lt;p&gt;So what’s the short version here? Clojure has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;s in order to
enable a dynamic rebinding model of programming which deployed
applications do not typically need. Because applications do not tend
to use dynamic binding for application code, we can discard &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;s and
directly use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IFn&lt;/code&gt; classes to which the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;s refer. This could
be a significant win just because it removes that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;volatile&lt;/code&gt; root on
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;s that poisons the JIT.&lt;/p&gt;

&lt;p&gt;This opens up more opportunities for playing tricks in the compiler,
because we don’t really need &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IFn&lt;/code&gt; objects for the most part. Remember
that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IFn&lt;/code&gt; objects are only needed because methods aren’t first class
on the JVM and to support dynamic redefinitions we need a first class
value for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;s to point to. If all definitions are static, then we
don’t need &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Var&lt;/code&gt;s, so we can find the fully qualified class and method
that a given function invocation points to, freeing a Clojure compiler
to do static method invocation. This should be a performance win as it
allows the JVM JIT to escape type checking of the object on which the
method is invoked and it allows the JIT to inline in the targeted
method among other tricks.&lt;/p&gt;

&lt;p&gt;If we can throw away &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IFn&lt;/code&gt;s by implementing functions as say static
methods on a namespace “class” rather than having seperate classes for
each function, then we cut down on program size in terms of classes
which should somewhat reduce the memory footprint of Clojure programs
on disk and in memory in addition to reducing load time.&lt;/p&gt;

&lt;h2 id=&quot;oxcart&quot;&gt;Oxcart&lt;/h2&gt;

&lt;p&gt;So what is Oxcart? Oxcart is a compiler for a subset of Clojure which
seeks to implement exactly the performance hat tricks specified above
and a few more. For the most part these are simple analysis operations
with well defined limitations. In fact, most of what’s required to use
Oxcart to compile Clojure code is already built and working in that
Oxcart can currently rewrite Clojure programs to aid and execute the
above transformations.&lt;/p&gt;

&lt;p&gt;Oxcart is also a huge exercise in the infrastructure around the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.tools.analyzer&lt;/code&gt; contrib library, as Oxcart is the first full
up compiler to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools.analyzer&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools.analyzer.jvm&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools.emitter.jvm&lt;/code&gt; as more than the direct compilation pipeline which
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools.emitter.jvm&lt;/code&gt; implements. This means that Oxcart has interesting
representational issues in how passes and analysis data are handled
and shared between passes, let alone how the data structure describing
the entire program is built and the performance limitations of various
possible representations thereof.&lt;/p&gt;

&lt;p&gt;So what’s Oxcart good for? right now: nothing. Oxcart doesn’t have an
AOT file emitter yet, and relies on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tools.emitter.jvm&lt;/code&gt; for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval&lt;/code&gt; and
as such is no faster for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval&lt;/code&gt;ing code in a live JVM than Clojure
is. At present I’m working on building an AOT emitter which will
enable me to start doing code generation and profiling Oxcart against
Clojure. I hope to post an initial emitter and a trivial benchmark
comparing a pair of mutually recursive math functions between Clojure
and Oxcart.&lt;/p&gt;

&lt;h2 id=&quot;before-you-go&quot;&gt;Before you go&lt;/h2&gt;

&lt;p&gt;I’ve know I’ve said this entire time that Oxcart is a Clojure
compiler. That’s a misnomer. Oxcart doesn’t compile Clojure and never
will. Clojure has stuff like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval-string&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resolve&lt;/code&gt;,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;load-string&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;load&lt;/code&gt; and all the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bindings&lt;/code&gt; stuff that allow Clojure
programmers to reach around the compiler’s back and change bindings
and definitions at runtime. These structures are not and never will be
supported by Oxcart because supporting them would require disabling
optimizations. Oxcart also doesn’t support non-def forms at the top
level. Oxcart programs are considered to be a set of defs and an entry
point. Oxcart also assumes that definitions are single. Redefining a
var is entirely unsupported, abet not yet a source of warnings.&lt;/p&gt;

&lt;p&gt;Some of these differences are sufficiently extreme that I’m honestly
on the fence about whether Oxcart is really Clojure or some yet
undefined “Oxlang” more in the style of Shen, but for now I’ll stick
to building a prototype &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:D&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;^D&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Typing the processor</title>
    <link href="https://www.arrdem.com/2013/11/13/typing-the-processor/"/>
    <updated>2013-11-13T00:00:00+00:00</updated>
    <id>https://www.arrdem.com/2013/11/13/typing-the-processor</id>
    <content type="html">&lt;p&gt;&lt;a href=&quot;/2014/01/05/a-pipeline-machine/&quot;&gt;Previously&lt;/a&gt; I implemented a
pipelined version of a simple processor for my batbridge assembly
architecture. This time, I’m going to take that architecture a step further by
using the &lt;a href=&quot;https://github.com/Clojure/core.typed&quot;&gt;Clojure.core.typed&lt;/a&gt; library by
@ambrosebs to get some level of type safety in preparation for a binary
assembler.&lt;/p&gt;

&lt;h2 id=&quot;introducing-typed-clojure&quot;&gt;Introducing typed Clojure&lt;/h2&gt;

&lt;p&gt;Clojure is at its core a typed language because the runtime that Clojure sits
upon (the Java JVM) is a type based system. However by a large the programming
model offered to Clojure programmers is essentially type agnostic. For the most
part, Clojure programmers are free to deal in terms of abstract sequence and map
types without real regard for the true Java class used to represent their data
at runtime.&lt;/p&gt;

&lt;p&gt;This is a Good Thing. It reduces the intellectual load on programmers in so much
as programmers are free to leave the implementation details of their algorithm
to the Clojure compiler. Unfortunately, types and their implications for data
operations are also more or less central to the way that programmers solve
problems. In short without some notion of types we are bound hand and foot.&lt;/p&gt;

&lt;p&gt;Typed Clojure as a library seeks to implement an optional annotative type system
for Clojure. Rather than enforce strict typing, Typed Clojure seeks to make
types a tool by which to ease evolving Clojure programs and an aid to program
comprehension rather than a set of implicit or comment noted assumptions.&lt;/p&gt;

&lt;p&gt;A personal example: This time last year I was tasked with writing an out of
order processor simulator for class (gee does that sound familiar). Everything
was going great until I discovered that I needed to add metadata to the
instructions in my simulator. Lots of metadata. Now at the time, I didn’t know
about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core/meta&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core/with-meta&lt;/code&gt; which make it possible to
attach metadata to existing objects. Rather I began the painful process of
reworking my simulator days before it was due from using a vector based
representation of an instruction to using a map. The results were unfortunate,
in so much as Maps it turns out are ISeq. This means that the sequence operators
which expected a Vector almost worked on maps making it a serious pain for me to
debug these type mismatches. As I said in my first post, the simulator never
quite worked.&lt;/p&gt;

&lt;p&gt;Typed Clojure helps resolve this class of problem by offering inference backed
annotative typing. This means that you describe through annotations what the
structure of your intended types are, and then a type inference engine attempts
to verify that your program is correct with respect to the described data
structures. So in the case of my map vs. vector instruction representation
problem, Typed Clojure checking would have made it obvious what code had not yet
been rewritten to operate on the instruction map rather than the previous
instruction vector structure.&lt;/p&gt;

&lt;h2 id=&quot;diving-in&quot;&gt;Diving in&lt;/h2&gt;

&lt;p&gt;As of this writing, Typed Clojure is at version
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[org.Clojure/core.typed &quot;0.2.17&quot;]&lt;/code&gt; and it is against this version that I will
be typing my current BatBridge simulator.&lt;/p&gt;

&lt;p&gt;Typed Clojure offers a number of built in types: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Seq&lt;/code&gt;s, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Set&lt;/code&gt;s, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Maps&lt;/code&gt;,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Integers&lt;/code&gt;, the list goes on and on. So just for grins, lets do a simple demo.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;demo&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:require&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Clojure.core.typed&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:as&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:refer&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;defn&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;t/ann&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;three&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/AnyInteger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;three&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;t/ann&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:no-check&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Clojure.core/zero?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/AnyInteger&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;t/ann&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myzero?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/AnyInteger&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;defn&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myzero?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;zero?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;defn&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add-two&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/AnyInteger&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/AnyInteger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
	    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
		
	&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/Anyinteger&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;more&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;t/Seq&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/AnyInteger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;more&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Type Clojure uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ann&lt;/code&gt; form to annotate a symbol with type(s). Here, I use
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ann&lt;/code&gt; form to indicate that the symbol &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;three&lt;/code&gt; is of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnyInteger&lt;/code&gt;. I
use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnyInteger&lt;/code&gt; rather than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;integer&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;long&lt;/code&gt; because Clojure typecasts
between long and integer under the covers, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnyInteger&lt;/code&gt; wraps both of them.&lt;/p&gt;

&lt;p&gt;I then defined a function, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;myzero?&lt;/code&gt;, which simply wraps &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core/zero?&lt;/code&gt;
annotating both my function and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core/zero?&lt;/code&gt; with the appropriate
types. For functions, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ann&lt;/code&gt; notation is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[param-type + -&amp;gt; ret-type]&lt;/code&gt;. Here,
I define both zero functions to be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[t/AnyInteger -&amp;gt; boolean]&lt;/code&gt;. This works as
expected, but when we run the typechecker on this namespace we will see that the
annotation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core/zero?&lt;/code&gt; warns that it isn’t being checked. This is
because I used the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^:no-check&lt;/code&gt; reader metadata when I annotated the symbol
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core/zero?&lt;/code&gt;. When the Typed Clojure type checker encounters
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^:no-check&lt;/code&gt; flagged symbols no effort is made to process the definition of the
annotated symbol and ensure that the annotative type is correct with respect to
the runtime type.&lt;/p&gt;

&lt;p&gt;Finally I use the new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;defn&amp;gt;&lt;/code&gt; syntax, to achieve the same sort of effect as my
previous &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;defn&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ann&lt;/code&gt; pair. In fact, if you inspect the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;defn&amp;gt;&lt;/code&gt; macro, you will
discover that it simply generates the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;defn&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ann&lt;/code&gt; pair. However it provides
nice syntactic sugar so I elected to demonstrate it.&lt;/p&gt;

&lt;h2 id=&quot;checking-types&quot;&gt;Checking types&lt;/h2&gt;

&lt;p&gt;There are three main entry points I use to typed Clojure:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core.typed/cf&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core.typed/check-ns&lt;/code&gt; and
&lt;a href=&quot;https://github.com/typedClojure/lein-typed&quot;&gt;lein-typed&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core.typed/cf&lt;/code&gt; (short for Check Form) is a function of two
arguments, the first being an expression for which some type is
claimed and the second being a type. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cf&lt;/code&gt; engages the Typed Clojure
inference engine and attempts to verify that the typed form is indeed
of the type claimed. For example, if we attempt to typecheck one of
the example forms above…&lt;/p&gt;

&lt;h2 id=&quot;introducing-seqs-maps-and-unions&quot;&gt;Introducing Seqs, Maps and Unions&lt;/h2&gt;

&lt;p&gt;Typed Clojure allows for considerably more variety in annotation than simple
types like integers and booleans. Sets and Maps are fully supported, through the
use of the forms &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core.typed/Set&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core.typed/Map&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As one would imagine, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core.typed/Set&lt;/code&gt; is a function of one argument,
which creates a type representing a set of elements which all share the argument
type.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core.typed/Map&lt;/code&gt; is similar, in that it is a function of two arguments,
one for the key type and one for the value type.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core.typed/Seq&lt;/code&gt; describes an arbitrary sequence of elements sharing a
type, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Clojure.core.type/Vec&lt;/code&gt; get the same place but is specific that the
sequence involved is a Vector.&lt;/p&gt;

&lt;p&gt;However we’re still in the realm of relatively simple types as far as Clojure is
concerned. Much of Clojure is about mixing and matching different types in and
out to create variable type structures and other kinds of weirdness. For this we
need three more forms:&lt;/p&gt;

&lt;h2 id=&quot;introducing-u-hmap-and-hvec&quot;&gt;Introducing U, HMap and HVec&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;U&lt;/code&gt; is the Typed Clojure function for expressing the union of several
types. That’s all it’s good for, but that makes it immensely powerful. Need to
represent a value which could be either &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Long&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Integer&lt;/code&gt;? &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(U Long
Integer)&lt;/code&gt;. Yes, it’s that easy.&lt;/p&gt;

&lt;p&gt;While still experimental, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HMap&lt;/code&gt; is for me where the rubber meets the road in
terms of Typed Clojure’s usefulness. Heterogeneous maps, maps where different
special keys map to differently typed values, are a core design pattern of the
Clojure community. As described over
&lt;a href=&quot;https://github.com/Clojure/core.typed/wiki/Types&quot;&gt;on the core.typed wiki&lt;/a&gt;,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HMaps&lt;/code&gt; can represent required keys, the types thereof, optional keys and the
types thereof, and even the absence of certain keys! &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HVec&lt;/code&gt; is the same idea as
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HMap&lt;/code&gt;, except that it’s used to represent Vectors rather than Maps.&lt;/p&gt;

&lt;h2 id=&quot;applying-this-to-batbridge&quot;&gt;Applying this to BatBridge&lt;/h2&gt;

&lt;p&gt;Okay. Well let’s start defining some of the types that are integral to the
BatBridge simulator then…&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;t/def-alias&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Memory&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A storage medium within a processor&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;t/Map&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/AnyInteger&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/AnyInteger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;t/def-alias&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Storage&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:registers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:memory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;t/def-alias&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InstructionParam&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;An instruction parameter&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/AnyInteger&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:r_PC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:r_IMM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:r_ZERO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;okay, cool… this lets us represent all the legal values which the simulator
could see as storage locations within the VM, and values that we can interpret
to put in those storage locations. Now let’s try and tackle the VM state
itself… we’re gonna need an HMap with a bunch of mandatory keys…&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;t/def-alias&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Processor&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A processor state&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;HMap&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:mandatory&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:registers&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Memory&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:memory&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Memory&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:fetch&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InstructionVec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:decode&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InstructionMap&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:execute&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CommitCommand&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:halted&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:complete?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;; indicates that anything else makes the Processor illegal&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;But what about the instructions themselves? We need three real instruction
encodings: the vector instructions which I use for my assembly notation, the map
instructions which execute operates on and which decode builds, and the commit
commands that writeback uses.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-clojure&quot; data-lang=&quot;clojure&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;t/def-alias&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InstructionVec&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A symbolic vector instruction&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/Keyword&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InstructionParam&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InstructionParam&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InstructionParam&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/AnyInteger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;t/def-alias&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InstructionMap&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A parsed map instruction&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;HMap&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:mandatory&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:icode&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/Keyword&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:dst&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InstructionParam&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:srca&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InstructionParam&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:srcb&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InstructionParam&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                    &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:lit&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/AnyInteger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:complete?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;t/def-alias&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CommitCommand&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:memory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/AnyInteger&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/AnyInteger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:registers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/AnyInteger&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t/AnyInteger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;:halt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now, armed with these type annotations, it’s more or less trivial to chase
through the simulator I originally presented adding the appropriate
annotations. However, all this comes to a head when you try and type the
processor’s memory because there is a fundamental type conflict in both of my
processors to date: both InstructionVecs and AnyIntegers are legal values within
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:memory&lt;/code&gt; of a Processor. This means that the type system cannot be sure
(and nor can we) that the value fetched from some address is in fact an
instruction not a value.&lt;/p&gt;

&lt;p&gt;There are two ways to resolve this conflict. The approach which I’ve
taken thus far if you’ve read the Typed Clojure code
&lt;a href=&quot;https://github.com/arrdem/batbridge/blob/master/src/batbridge/pipeline.clj&quot;&gt;over on github&lt;/a&gt;
is to sweep this conflict under the rug by creating a pair of
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^:no-check&lt;/code&gt; functions one of which reads memory returning
instructions, the other of which reads memory returning
values. However the real fix to this is to introduce a binary
(numeric) encoding for instructions. I hope that this constitutes a
helpful introduction to Typed Clojure, next time I will at long last
define an encoding for BatBridge and present the full architecture
complete with a bytecode assembler toolkit.&lt;/p&gt;

&lt;p&gt;^d&lt;/p&gt;
</content>
  </entry>
  
</feed>
