<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3016981170905406325</id><updated>2026-09-26T18:48:40.298-07:00</updated><category term="Common Lisp"/><category term="Idea Peeling"/><category term="Programming Environment"/><category term="Speculation"/><category term="General Programming Thoughts"/><category term="Almost Literate Programming"/><category term="Bitching"/><category term="Haskell"/><category term="Programming Interfaces"/><category term="Emacs"/><category term="Hardware"/><category term="JavaScript"/><category term="Erlang"/><category term="Python"/><category term="Elisp"/><category term="jQuery"/><category term="HTML"/><category term="HTML5"/><category term="Hunchentoot"/><category term="Languages"/><category term="Security"/><category term="Client Side"/><category term="Clojure"/><category term="Databases"/><category term="Lisp"/><category term="Parenscript"/><category term="CLOS"/><category term="Elm"/><category term="Flow Based Programming"/><category term="Scheme"/><category term="Shell"/><category term="Journal"/><category term="git"/><category term="snippets"/><category term="C"/><category term="General Update"/><category term="PHP"/><category term="Rebol"/><category term="Ruby"/><category term="notes"/><category term="CSS"/><category term="Copyright Bullshit"/><category term="FFI"/><category term="Free Software"/><category term="Response"/><category term="Smalltalk"/><category term="Syntax"/><category term="Video Games"/><category term="cl-notebook"/><category term="cl-sql"/><category term="make"/><category term="Almost Literate Cooking"/><category term="Angularjs"/><category term="Coffee Script"/><category term="Comet"/><category term="Daimio"/><category term="Ereader"/><category term="Forth"/><category term="Hosting"/><category term="In Memoriam"/><category term="Indentation"/><category term="Media"/><category term="Nitrogen"/><category term="Patents"/><category term="Pathnames"/><category term="PostScript"/><category term="User Group"/><category term="Websockets"/><category term="cl-smtp"/><category term="code-retreat notes"/><title type='text'>language agnostic</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>194</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-5840794412111035601</id><published>2014-06-13T07:46:00.001-07:00</published><updated>2014-06-13T07:47:08.662-07:00</updated><title type='text'>The Blog Has Moved</title><content type='html'>&lt;p&gt;&lt;code&gt;langnostic.blogspot&lt;/code&gt; has moved to &lt;a href=&quot;http://langnostic.inaimathi.ca/&quot;&gt;langnostic.inaimathi.ca&lt;/a&gt; (also, &lt;a href=&quot;http://langnostic.inaimathi.ca/feed/atom&quot;&gt;atom feed here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The archives will remain for posterity, but any new posts are probably going to happen there rather than here.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/5840794412111035601/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2014/06/the-blog-has-moved.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/5840794412111035601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/5840794412111035601'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2014/06/the-blog-has-moved.html' title='The Blog Has Moved'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-2511243863177399235</id><published>2014-05-20T19:36:00.000-07:00</published><updated>2014-05-21T07:35:35.623-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="General Programming Thoughts"/><category scheme="http://www.blogger.com/atom/ns#" term="General Update"/><category scheme="http://www.blogger.com/atom/ns#" term="Idea Peeling"/><title type='text'>Arbitrary Update 932</title><content type='html'>&lt;p&gt;It&#39;s been a while. Sadly/happily, I&#39;ve been busy working on the &lt;a href=&quot;https://github.com/Inaimathi/500lines/blob/master/async-web-server/writeup.md&quot;&gt;&lt;code&gt;house&lt;/code&gt; write-up&lt;/a&gt; for &lt;a href=&quot;http://aosabook.org/blog/&quot;&gt;AOSA 4&lt;/a&gt; and thinking pretty hard about a &lt;a href=&quot;https://github.com/Inaimathi/cl-notebook&quot;&gt;&lt;code&gt;cl-notebook&lt;/code&gt;&lt;/a&gt;-related submission to &lt;a href=&quot;http://www.future-programming.org/call.html&quot;&gt;this&lt;/a&gt;, so any spare writing time I&#39;ve had has been getting pointed directly away from this blog. This is going to be a pretty incoherent update, mainly focused at getting various things out of my head rather than making any kind of sense. It&#39;s a quick cross-section/pressure-release related to things I&#39;ve been thinking about lately, not a catalyst for learning or external discussion.&lt;/p&gt;

&lt;h3&gt;cl-notebook/fact-base&lt;/h3&gt;

&lt;p&gt;I&#39;m noticing that there&#39;s a very common pattern in the &lt;a href=&quot;https://github.com/Inaimathi/cl-notebook&quot;&gt;&lt;code&gt;cl-notebook&lt;/code&gt;&lt;/a&gt; use-case for &lt;a href=&quot;https://github.com/Inaimathi/fact-base&quot;&gt;&lt;code&gt;fact-base&lt;/code&gt;&lt;/a&gt;. Specifically, the deletion of a record followed by the insertion of a very similar new record.&lt;/p&gt;

&lt;pre&gt;  (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((cont-fact (first (lookup book &lt;span style=&quot;color: #483d8b;&quot;&gt;:a&lt;/span&gt; cell-id &lt;span style=&quot;color: #483d8b;&quot;&gt;:b&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:contents&lt;/span&gt;)))
        (val-fact (first (lookup book &lt;span style=&quot;color: #483d8b;&quot;&gt;:a&lt;/span&gt; cell-id &lt;span style=&quot;color: #483d8b;&quot;&gt;:b&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:result&lt;/span&gt;)))
        (cell-lang (caddar (lookup book &lt;span style=&quot;color: #483d8b;&quot;&gt;:a&lt;/span&gt; cell-id &lt;span style=&quot;color: #483d8b;&quot;&gt;:b&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:cell-language&lt;/span&gt;)))
        (cell-type (caddar (lookup book &lt;span style=&quot;color: #483d8b;&quot;&gt;:a&lt;/span&gt; cell-id &lt;span style=&quot;color: #483d8b;&quot;&gt;:b&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:cell-type&lt;/span&gt;))))
    (delete! book cont-fact)
    (insert! book (list cell-id &lt;span style=&quot;color: #483d8b;&quot;&gt;:contents&lt;/span&gt; contents))
    (publish! &lt;span style=&quot;color: #483d8b;&quot;&gt;:cl-notebook-updates&lt;/span&gt; (update &lt;span style=&quot;color: #483d8b;&quot;&gt;:book&lt;/span&gt; (notebook-name book) &lt;span style=&quot;color: #483d8b;&quot;&gt;:cell&lt;/span&gt; cell-id &lt;span style=&quot;color: #483d8b;&quot;&gt;:action&lt;/span&gt; &#39;content-changed &lt;span style=&quot;color: #483d8b;&quot;&gt;:contents&lt;/span&gt; contents))
  ...&lt;/pre&gt;

&lt;p&gt;What I&#39;m trying to express there is a change in an existing record. It&#39;s mildly annoying for two reasons. First, it means that I need to effectively store every change twice in the form of a before-and-after shot (which, granted, I kind of need to keep doing if I want easy reversibility on edits). Second, and more importantly, it means that a history interface for something being backed by a fact base is going to need to be more complex than I&#39;d like. Instead of naively displaying states, I&#39;ll need to make sure to intelligently handle the situation where a user moves history to a point between a deletion and new insertion of a particular fact. I&#39;m going to shortly be making such an interface for &lt;code&gt;cl-notebook&lt;/code&gt;, so this is going to get painfully relevant very soon. This has me seriously considering adding a third token to &lt;code&gt;fact-base&lt;/code&gt;, &lt;code&gt;:modify&lt;/code&gt;, specifically to address this.&lt;/p&gt;

&lt;h3&gt;Memory&lt;/h3&gt;

&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi68h6bWK6hHUV-Y-cCIrz-Z_ru3_hfxS4LbZPzbtIa9_cBTQF4jLTSyrFX0K71JXogr9kr7CWSo-MubanD6Ef9H-3IxcZjE7XLvAbCsUsMHCT48um2hOc7kWC1py6VrtvFTDaBAyH124xT/s1600/thinkin-bout-memory-management.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi68h6bWK6hHUV-Y-cCIrz-Z_ru3_hfxS4LbZPzbtIa9_cBTQF4jLTSyrFX0K71JXogr9kr7CWSo-MubanD6Ef9H-3IxcZjE7XLvAbCsUsMHCT48um2hOc7kWC1py6VrtvFTDaBAyH124xT/s320/thinkin-bout-memory-management.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Whatever language you&#39;re currently using, managing memory is something that you&#39;re ultimately doing. Whether it&#39;s manually, or through various schemes that do it on your behalf. The ultimate goal of all of these approaches is twofold:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;make sure that a new allocation doesn&#39;t clobber a chunk of memory that&#39;s still being used by something&lt;/li&gt;
  &lt;li&gt;make sure that you never build up enough memory junk that you can&#39;t allocate a new block when you need to&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The general approaches seem to be&lt;/p&gt;

&lt;h2&gt;Not&lt;/h2&gt;

&lt;p&gt;For sufficiently short-running programs, a reasonable approach is to just build up junk constantly and let it come out in the wash after the program ends. This is a pretty narrow use case, since you can&#39;t clobber memory held by another program, and you can&#39;t use more memory than exists on the machine running you, but it&#39;s sometimes an option. I&#39;m... not actually aware of a language that takes this approach.&lt;/p&gt;

&lt;h2&gt;Manual&lt;/h2&gt;

&lt;p&gt;This is the C/C++ approach. You, the programmer, get to declare exactly what pieces are being used and when. Whether that&#39;s on a procedure-by-procedure or datastructure-by-datastructure basis, you&#39;re ultimately responsible for memory yourself directly. The upside is that there&#39;s no garbage collection overhead. The downside is that every procedure/datastructure has to manage memory acceptably, otherwise things start blowing up in various hard-to-diagnose ways.&lt;/p&gt;

&lt;h2&gt;Mark-and-sweep and variants&lt;/h2&gt;

&lt;p&gt;One of the automatic memory management approaches. The general idea here is&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;keep a free memory list, and track of all things allocated by the program&lt;/li&gt;
  &lt;li&gt;every so often (either at a time interval, or every &lt;code&gt;n&lt;/code&gt; allocations, or maybe just when you try to allocate memory and your free list is empty), traverse the list of all things and free the ones that aren&#39;t being used any more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A variant on this known as &lt;b&gt;generational garbage collection&lt;/b&gt; is keeping several buckets of allocated things, rather than one. You&#39;d partition objects based on how long they&#39;ve been around so that you don&#39;t waste much time traversing long-lived data every time through. This is the variant that I&#39;ve seen discussed most often, and I kind of get the impression that it&#39;s also the one getting the most research time thrown at it, but I&#39;m not entirely sure why. Oh, incidentally, languages like Common Lisp, Java and Python use this one.&lt;/p&gt;

&lt;h2&gt;Reference-counting&lt;/h2&gt;

&lt;p&gt;Another automatic approach, also known as &lt;b&gt;deterministic garbage collection&lt;/b&gt;. As far as I understand, Perl does this. The idea is to keep a special eye on language primitives that create or destroy references to objects, and to keep track of how many references to a particular object exist. Every time a relevant primitive is called, modify the reference count for the target, and collect it if that count is zero afterwards. I&#39;m not sure what the pitfalls are in practice, but there seems to be a lot less discussion about this approach than about the previous.&lt;/p&gt;

&lt;h2&gt;Circular Memory&lt;/h2&gt;

&lt;p&gt;I only vaguely understand this one, and from what I understand, it&#39;s fairly limited, but here goes. The situation you&#39;d want to use this or something like it is when a particular allocation is only needed for a short time before being discarded, and can be discarded sequentially. If you&#39;re in that situation, what you can do is figure out how much memory you have, then allocate things to it in order and hop back to the beginning when you&#39;re done. You need a pointer to the next block you can use (which you update every time you need to allocate a new thing), and a pointer to the first still-relevant block (which you update every time you free something). If the two ever overlap, you know you have a problem. Shapes other than circular are possible. For instance, you could have some sort of self-referential tree structure that accomplishes the same thing for mildly different use cases.&lt;/p&gt;

&lt;h3&gt;Decentralization&lt;/h3&gt;

&lt;p&gt;This isn&#39;t a thing related to memory; this is separate.&lt;/p&gt;

&lt;p&gt;I&#39;ve got this pattern of&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;assuming problem &lt;code&gt;foo&lt;/code&gt; is solved&lt;/li&gt;
  &lt;li&gt;going on about my business for a while&lt;/li&gt;
  &lt;li&gt;taking a close look at &lt;code&gt;foo&lt;/code&gt; for the purposes of implementing something related to it&lt;/li&gt;
  &lt;li&gt;suddenly realizing that &lt;code&gt;foo&lt;/code&gt; is not only unsolved, but can&#39;t possibly &lt;i&gt;be&lt;/i&gt; solved&lt;/li&gt;
  &lt;li&gt;thinking about it really hard in an obsessive/compulsive sort of way&lt;/li&gt;
  &lt;li&gt;learning to live with a deep dissatisfaction about some small part of the universe&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This has happened for identity, free will, type systems, &lt;a href=&quot;http://langnostic.blogspot.ca/2012/03/strifebarge-update-and-my-secure.html&quot;&gt;authentication&lt;/a&gt;, and most recently decentralization.&lt;/p&gt;

&lt;p&gt;More will follow, I&#39;m sure.&lt;/p&gt;

&lt;p&gt;I heard about the &lt;a href=&quot;http://stackoverflow.com/questions/1032006/will-html5-allow-web-apps-to-make-peer-to-peer-http-connections&quot;&gt;peer-to-peer connection mechanisms in development for HTML5&lt;/a&gt;, and figured it would be nice to put something nice and small together using it. To that end, I&#39;d absorbed and discussed the idea of &lt;a href=&quot;http://en.wikipedia.org/wiki/Mental_poker&quot;&gt;mental poker&lt;/a&gt; with a couple of people, and thought I had the hard parts under control. It turns out that this new set of functionality is still going to need central servers to set up the connections though, at which point I dismissed the approach only to notice a cognitive rupture. &lt;i&gt;Every&lt;/i&gt; &quot;distributed&quot; protocol seems to need a central server to bootstrap. The web needs DNS, torrents need trackers, cell-phones need satellites and/or transmission stations, etc etc.&lt;/p&gt;

&lt;p&gt;This fundamentally shifts the problem in my mind. If we&#39;re going to be burdened with some central functional cluster &lt;i&gt;anyway&lt;/i&gt;, it looks like a better problem to solve might be &quot;how do we perform tasks with multiple &#39;central&#39; clusters&quot; rather than &quot;how do we have as few central structures as possible&quot;.&lt;/p&gt;

&lt;p&gt;Fuck you if it doesn&#39;t make sense. It&#39;s late and I&#39;m piping a stream of consciousness here. I was also going to talk about a few other things on my mind; assembler and some new revelations about Flow Based Programming in particular, but I&#39;m about to lose coherence entirely, and nobody wants that.&lt;/p&gt;

&lt;p&gt;I&#39;ll let you know what, if anything, comes of any of these meditations. For the moment, you&#39;ll have to tolerate some more radio silence.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/2511243863177399235/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2014/05/arbitrary-update-932.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/2511243863177399235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/2511243863177399235'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2014/05/arbitrary-update-932.html' title='Arbitrary Update 932'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi68h6bWK6hHUV-Y-cCIrz-Z_ru3_hfxS4LbZPzbtIa9_cBTQF4jLTSyrFX0K71JXogr9kr7CWSo-MubanD6Ef9H-3IxcZjE7XLvAbCsUsMHCT48um2hOc7kWC1py6VrtvFTDaBAyH124xT/s72-c/thinkin-bout-memory-management.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-9084101430598927743</id><published>2014-04-21T17:28:00.000-07:00</published><updated>2014-04-23T08:21:51.472-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="cl-notebook"/><category scheme="http://www.blogger.com/atom/ns#" term="General Programming Thoughts"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming Environment"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming Interfaces"/><title type='text'>cl-notebook Thoughts</title><content type='html'>&lt;STYLE TYPE=&quot;text/css&quot; MEDIA=&quot;screen&quot;&gt;&lt;!--
.cm-s-default .cm-keyword {color: #708;}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
.cm-s-default .cm-variable {color: black;}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3 {color: #085;}
.cm-s-default .cm-property {color: black;}
.cm-s-default .cm-operator {color: black;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.cm-s-default .cm-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}
.cm-s-default .cm-error {color: #f00;}

.result { border: 1px solid #ccc; background-color: #fff; list-style-type: none; margin: 0px; margin-top: 5px; padding: 0px; }
.stdout { margin: 0px; padding: 5px; color: #8b2252; background-color: #efefef; }
.result li { padding: 5px; }
.result .type { color: #228b22; }
.warnings .condition-contents { background-color: #fc6; color: #c60; border: 1px solid #c60; padding: 5px; margin: 5px 0px; }
.result .error { background-color: #fdd; color: #933; }
.condition-contents { list-style-type: none; margin: 0px; padding: 0px; }
.condition-contents .condition-type { font-weight: bolder; }
.condition-contents .condition-property { font-style: oblique; }
.condition-contents .condition-property .label { display: inline-block; margin-right: 5px; font-size: small; }
--&gt;&lt;/STYLE&gt;&lt;p&gt;No nuts and bolts this time. Here&#39;s a random collection of insights I&#39;ve had while trying to put together the version 0.1 of a notebook style editor:&lt;/p&gt;&lt;h3&gt;Being async Pays&lt;/h3&gt;&lt;p&gt;My initial assumption was that evaluation would be an inline thing. That is, you send out a &lt;code&gt;POST&lt;/code&gt; request, that code is evaluated synchronously, saved out to your fact base, and the HTTP response consists of that evaluated result which you can then display prettily on the front-end. Turns out that&#39;s a big fat no. Even discounting any issues with the Common Lisp return model, and the eventual attempt at making this a multi-user editor, the synchronous approach doesn&#39;t quite work. Which I found out the first time I accidentally wrote a &lt;code&gt;loop&lt;/code&gt; without the required &lt;code&gt;while&lt;/code&gt;. Something like&lt;/p&gt;&lt;pre class=&quot;cm-s-default&quot;&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-builtin&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;cm-builtin&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;pop&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;stack&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-builtin&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;something-to-next&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;The trouble should be obvious. That&#39;s the sort of computation that you want off in its own isolated thread. And you want to be able to kill that thread if it turns out to be as boneheaded a mistake as that was, which means that you have to notify the front-end of computations in progress, go off and perform it, then notify the front-end again when you&#39;re done. And that&#39;s not something you can do synchronously.&lt;/p&gt;&lt;p&gt;In the end, I end up spawning a single tracked thread to do the work of evaluation. I notify the front-ends when it begins work, and then again when it completes. At any point in between, a front-end can send a termination signal to kill that thread rather than waiting it out to completion. You can see the implementation &lt;a href=&#39;https://github.com/Inaimathi/cl-notebook/blob/master/cl-notebook.lisp#L51-L70&#39;&gt;here&lt;/a&gt;, &lt;a href=&#39;https://github.com/Inaimathi/cl-notebook/blob/master/cl-notebook.lisp#L162-L163&#39;&gt;here&lt;/a&gt;, and &lt;a href=&#39;https://github.com/Inaimathi/cl-notebook/blob/master/cl-notebook.lisp#L126-L131&#39;&gt;here&lt;/a&gt;. This will &lt;i&gt;entirely&lt;/i&gt; coincidentally make it much easier to extend &lt;code&gt;cl-notebook&lt;/code&gt; to a multi-user editor later.&lt;/p&gt;&lt;h3&gt;Being surgical pays. Sometimes. Not in the way you&#39;d think.&lt;/h3&gt;&lt;p&gt;The first version of this editor basically spat out the complete current notebook state at the front-end on each action, and the front-end re-drew &lt;i&gt;the entire thing&lt;/i&gt; on every change. You&#39;d think that the sheer inefficiency of this approach would get to me, but you&#39;d be wrong. It was actually fast enough that had performance been the only factor, I&#39;d have left it at that. The problem with that approach is that you end up clobbering giant chunks of client-side state each time. In particular, re-drawing every cell (and hence, re-initializing each of their &lt;code&gt;CodeMirror&lt;/code&gt; instances) meant that I was blowing away undo information for each editor window every time &lt;i&gt;anything&lt;/i&gt; happened. And that&#39;s annoying as fuck. I&#39;m not sure anyone&#39;s formalized the point into a commandment yet, but you really should act as though they have: Thou Shalt Not Mangle Thy Clients&#39; Data. That applies no matter how temporary the data is. Even if your job is to take said data and transform it in some way, say for instance by evaluating it, you should do so with a copy instead of a destructive change. And even when you absolutely &lt;i&gt;must&lt;/i&gt; be destructive, be as selectively destructive as you possibly can.&lt;/p&gt;&lt;h3&gt;Thinking About Space Doesn&#39;t Pay. No, not even that much.&lt;/h3&gt;&lt;p&gt;I almost left this one out entirely because it seemed so self-evident, but on reflection, it&#39;s something I&#39;ve had to learn too. Space doesn&#39;t even begin to matter for systems like this. I&#39;m talking both about memory and about disk space. Yes, there are some applications for which this is not the case, but it&#39;s true as a rule.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;fact-base&lt;/code&gt; project in particular has been sticking in my craw in this sense. I kept thinking things like &#39;Holy shit, I&#39;m keeping history for every cell, on every edit forever. This is going to be huge! I&#39;ll have to figure out a way to condense these files, or start them off from a non-zero state so that I can throw out history at some point!&#39;&lt;/p&gt;&lt;p&gt;Completely pointless.&lt;/p&gt;&lt;p&gt;At the beginning of the &lt;code&gt;cl-notebook&lt;/code&gt; effort, I started a scratch file which I&#39;ve been steadily editing, putting through various save/auto-save tests and just all round mauling with updates. This thing has been around for months at this point, and it&#39;s taken much harder beatings than the average notebook ever will. Wanna know what its current total size is?&lt;/p&gt;&lt;pre&gt;inaimathi@self:~/.cl-notebook/books$ ls -lh base-zg1mm23z
-rw-r--r-- 1 inaimathi inaimathi 675K Apr 20 21:47 base-zg1mm23z
inaimathi@self:~/.cl-notebook/books$&lt;/pre&gt;&lt;p&gt;That&#39;s smaller than many Word and PDF documents I&#39;ve worked with, and those don&#39;t bother keeping my entire editing history around. So I figure I can get away with treating disk space as if it were infinite for my purposes. Absolute worst case scenario, I&#39;ll compress it. And since I&#39;m dealing with plaintext files, that should be rather effective.&lt;/p&gt;&lt;pre&gt;inaimathi@self:~/.cl-notebook/books$ pack -t tar.gz base-zg1mm23z
base-zg1mm23z
inaimathi@self:~/.cl-notebook/books$ ls -lh base-zg1mm*
-rw-r--r-- 1 inaimathi inaimathi 675K Apr 20 21:47 base-zg1mm23z
-rw-r--r-- 1 inaimathi inaimathi  23K Apr 20 21:47 base-zg1mm23z.tar.gz&lt;/pre&gt;&lt;p&gt;Yeah. I think that&#39;ll be good enough.&lt;/p&gt;&lt;h3&gt;Return Values are Complicated&lt;/h3&gt;&lt;p&gt;I mean, I knew that already, but it turns out there are even more intricacies here. I initially assumed I&#39;d be able to just keep a single return value per cell (by which I mean the return from a single Lisp function, which can be zero, one or more values). Then it hit me that a &lt;code&gt;cell&lt;/code&gt; might have more than one expression in it. &lt;i&gt;Then&lt;/i&gt; it hit me that return values aren&#39;t enough; you need to be able to handle &lt;code&gt;*standard-output*&lt;/code&gt; emissions and warnings on a per-expression basis rather than on a per-cell basis, and that we&#39;d want type annotations in some places since we&#39;ll be serializing various things to strings and it would otherwise get confusing. Then &lt;i&gt;I&lt;/i&gt; hit me and sat down to write down something workable. Each cell now stores a &lt;code&gt;result&lt;/code&gt;, which is zero or more &lt;code&gt;values&lt;/code&gt;, each of which is actually a &lt;code&gt;value&lt;/code&gt; and a &lt;code&gt;type&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;That lets the front end figure out what it needs to do on a per cell basis, which means that the server-side implementation of a cells&#39; &lt;code&gt;noise&lt;/code&gt; becomes very mechanically simple. It&#39;s basically just an extra fact we keep around as a label, which the front-end queries to decide how to transform the high-detail &lt;code&gt;result&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;&lt;code&gt;cell-type&lt;/code&gt; is not the same thing as &lt;code&gt;cell-language&lt;/code&gt;&lt;/h3&gt;&lt;p&gt;Early on, I had this idea that I&#39;d be semi-implicit about what&#39;s in a cell. At that point there were two &lt;code&gt;cell-type&lt;/code&gt;s; &lt;code&gt;common-lisp&lt;/code&gt; and &lt;code&gt;cl-who&lt;/code&gt;. The idea would be that this single &lt;code&gt;cell-type&lt;/code&gt; would determine both display and evaluation properties of the contained code. Nope, as it turns out. And the thing that finally made this clear to me is thinking about how I&#39;d treat test code. It&#39;s still Common Lisp, you see, so I&#39;d still be evaluating it the same way as any other code cell, but I didn&#39;t want it showing up in certain exports.&lt;/p&gt;&lt;p&gt;The solution I ended up settling on is to be explicit about everything. Each cell now has a &lt;code&gt;cell-type&lt;/code&gt; as well as a &lt;code&gt;cell-language&lt;/code&gt;. The first one being one of &lt;code&gt;markup&lt;/code&gt; (for prose blocks), &lt;code&gt;code&lt;/code&gt; (for code blocks), and &lt;code&gt;tests&lt;/code&gt; (for code blocks that I&#39;d want to separate from actual runtime code).&lt;/p&gt;&lt;h3&gt;Naming things is difficult&lt;/h3&gt;&lt;p&gt;I think there&#39;s a joke about this somewhere. Something along the lines of &lt;/p&gt;&lt;blockquote&gt;The only two difficult problems in programming are naming things, cache invalidation and off-by-one errors.&lt;/blockquote&gt;&lt;p&gt;and man did that ever bite me this time. It&#39;s obviously bad to tie the file-system name of something to its display name, if for no reason other than it opens up various injection vectors that you&#39;d rather not open up. It turns out it gets even more complicated when you&#39;re dealing with history trees of various documents, and you&#39;re trying to reduce headaches for your users. Here, think about this problem for a bit. Say you had a document type that you&#39;d let your users name. We&#39;re obviously not naming the on-disk file after the display name of the document, so this is a matter of storing a record in the document that&#39;ll keep a user-entered name around for reference purposes. That gives you the additional benefit of being able to roll back renames, and the ability to see what a given document was called at some point in the past. Now, say you want to be able to branch said document. That is, instead of being a single history line, you want to be able to designate certain timelines as belonging to different branches than others. What you need now is four different levels of naming. Five, depending on how ham-handedly you&#39;ve decided to store and relate those branches. At minimum you need&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The filename of the document, which is different from&lt;/li&gt;&lt;li&gt;The display name of the same document (which might be different in different branches, and at different points in time), which is different from&lt;/li&gt;&lt;li&gt;The display name of a particular branch of the document (which might need to be human readable, or user entered) which is different from&lt;/li&gt;&lt;li&gt;The collective, still human-readable name for a set of branches belonging to one document.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If you&#39;ve stored a branch collective as a file/folder on disk, you&#39;ll have to name that too. So, what would you do?&lt;/p&gt;&lt;p&gt;Confronted with this problem, I punted. Branching is basically going to be a copying operation. What you&#39;ll eventually get, once I put the branching system together and you try to use it, is a complete, self-contained fact base that happens to (possibly temporarily) have the same display-name as its origin (plus the word &#39;branch&#39;), and a fact or two that point to a specific time point in that origin. From there, they&#39;ll diverge and be entirely separate entities. No, I&#39;m not entirely sure this is the best approach, or even an acceptable approach, but it seems to be the only way to avoid asking the user to manage four different names in the space of one document. So I&#39;ll take it.&lt;/p&gt;&lt;p&gt;There&#39;s probably more where those came from, but they&#39;re all I could pull out of my head at short-ish notice. I&#39;ll try to let you know how the rest of the project goes, as it happens.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/9084101430598927743/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2014/04/cl-notebook-thoughts.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/9084101430598927743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/9084101430598927743'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2014/04/cl-notebook-thoughts.html' title='cl-notebook Thoughts'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-2302976596171947107</id><published>2014-04-20T18:49:00.000-07:00</published><updated>2014-04-20T18:49:54.990-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="cl-notebook"/><category scheme="http://www.blogger.com/atom/ns#" term="Common Lisp"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming Environment"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming Interfaces"/><title type='text'>cl-notebook Introductory Thoughts</title><content type='html'>&lt;STYLE TYPE=&quot;text/css&quot; MEDIA=&quot;screen&quot;&gt;&lt;!--
.cm-s-default .cm-keyword {color: #708;}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
.cm-s-default .cm-variable {color: black;}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3 {color: #085;}
.cm-s-default .cm-property {color: black;}
.cm-s-default .cm-operator {color: black;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.cm-s-default .cm-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}
.cm-s-default .cm-error {color: #f00;}

.result { border: 1px solid #ccc; background-color: #fff; list-style-type: none; margin: 0px; margin-top: 5px; padding: 0px; }
.stdout { margin: 0px; padding: 5px; color: #8b2252; background-color: #efefef; }
.result li { padding: 5px; }
.result .type { color: #228b22; }
.warnings .condition-contents { background-color: #fc6; color: #c60; border: 1px solid #c60; padding: 5px; margin: 5px 0px; }
.result .error { background-color: #fdd; color: #933; }
.condition-contents { list-style-type: none; margin: 0px; padding: 0px; }
.condition-contents .condition-type { font-weight: bolder; }
.condition-contents .condition-property { font-style: oblique; }
.condition-contents .condition-property .label { display: inline-block; margin-right: 5px; font-size: small; }
--&gt;&lt;/STYLE&gt;&lt;p&gt;So it&#39;s about time I talked about &lt;a href=&#39;https://github.com/Inaimathi/cl-notebook&#39;&gt;this thing&lt;/a&gt;, and what the hell exactly I&#39;m thinking. Because I&#39;ve been working on it for a while, and while it&#39;s still kind of buggy, I&#39;ve already found myself wanting some of the features it has when working with Emacs, or other text editors I&#39;ve had to work with.&lt;/p&gt;&lt;h3&gt;Notebooks&lt;/h3&gt;&lt;p&gt;Actually, before I get to that, a little exposition. As far as I know, notebook-style editors already exist for &lt;a href=&#39;http://ipython.org/notebook.html&#39;&gt;Python&lt;/a&gt;, &lt;a href=&#39;https://github.com/ramnathv/rNotebook&#39;&gt;R&lt;/a&gt;, and &lt;a href=&#39;http://gorilla-repl.org/index.html&#39;&gt;Clojure&lt;/a&gt;. And a second one for &lt;a href=&#39;https://github.com/kovasb/session&#39;&gt;Clojure&lt;/a&gt;. The general idea is to have a web-based interface, with code being divided into small, re-arrangable chunks called &lt;code&gt;cells&lt;/code&gt;, each of which are associated with their evluation results. Some cells are code in whichever language the notebook supports, others are just prose, usually in &lt;code&gt;markdown&lt;/code&gt;. The idea is that you get a dynamic environment that lets you selectively evaluate small chunklets of code, and intersperse relevant documentation in the form of prose and tests.&lt;/p&gt;&lt;p&gt;As someone who&#39;s been eyeing &lt;a href=&#39;http://literateprogramming.com/&#39;&gt;literate programming techniques&lt;/a&gt; for a while, this predictably appeals to me. So I&#39;ve built my own, for my language of choice.&lt;/p&gt;&lt;h3&gt;&lt;code&gt;cl-notebook&lt;/code&gt;&lt;/h3&gt;&lt;p&gt;You can find it at the other end of &lt;a href=&#39;https://github.com/Inaimathi/cl-notebook&#39;&gt;that github link I start out with&lt;/a&gt;. Last time I &lt;a href=&#39;http://langnostic.blogspot.ca/2014/03/housekeeping.html&#39;&gt;mentioned this project&lt;/a&gt; in passing, I noted that the ultimate goal was replacing Emacs as my Common Lisp IDE of choice, and that&#39;s no small task. Despite the existence of &lt;a href=&#39;https://github.com/achengs/subpar&#39;&gt;&lt;code&gt;subpar&lt;/code&gt;&lt;/a&gt;, I don&#39;t have proper s-expression navigation yet, and I haven&#39;t wired up proper auto-completion or argument hinting yet, and there&#39;s a bunch of other stuff I still want to build, ranging from the necessary to the frivolous. On the whole, I think I&#39;m on the right track, because certain things are somewhat easier here, and because there are some features that I find myself missing when I hop back into &lt;code&gt;emacs&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Lets just get those out of the way right now, actually. Firstly, I get to program in my browser, which is surprisingly elegant once I hop into full-screen mode. It lets me tab over to search for relevant links to talk about, and since my browser can be set to start up with previously open tabs, I get to resume editing exactly where I was in a later session. Secondly, because of the &lt;a href=&#39;https://github.com/Inaimathi/fact-base&#39;&gt;back-end storage system I&#39;m using&lt;/a&gt;, I get to have a running history of all the edits I&#39;ve ever made, which is updated every time I evaluate a cell (I&#39;m working on having it implicitly updated every so often between evaluations, but don&#39;t have that part checked in). Thirdly, I&#39;ve got exporters wired up that let me put together a book, then export it as an HTML page, or as a &lt;code&gt;.lisp&lt;/code&gt; file. And I&#39;m planning to add two more, one to just extract tests and a second to just hand me an executable from the given book.&lt;/p&gt;&lt;p&gt;The first one is minor, and makes it all the easier to randomly check my email or github notifications, so pros and cons. The third could concievably be wired together in Emacs. The second one is huge. I don&#39;t know about you, but I&#39;ve been programmed to hit &lt;code&gt;save&lt;/code&gt; every few seconds in whatever editor I&#39;ve got open just because crashes happen, and I don&#39;t want them to be too painful. I guess I could have wired up &lt;code&gt;emacs&lt;/code&gt; to do that every so often, but it sounds fiddly as hell. You don&#39;t particularly &lt;i&gt;want&lt;/i&gt; a standard editor saving every three seconds or so; you might be in the middle of an edit the currently keyed-in part of which doesn&#39;t make sense by itself, and most editors &#39;save&#39; by &lt;i&gt;overwriting your existing file&lt;/i&gt;. Which is exactly what you don&#39;t want when you&#39;ve got an unfinished code edit. Hopefully, adding total-history retention to the equation softens the blow.&lt;/p&gt;&lt;h3&gt;Core Concepts&lt;/h3&gt;&lt;p&gt;Code is organized into &lt;code&gt;book&lt;/code&gt;s. Each &lt;code&gt;book&lt;/code&gt; is the complete history of a bunch of &lt;code&gt;cell&lt;/code&gt;s. A &lt;code&gt;cell&lt;/code&gt; can contain &lt;code&gt;code&lt;/code&gt;, &lt;code&gt;tests&lt;/code&gt;, or &lt;code&gt;markup&lt;/code&gt; in a particular language (currently just Common Lisp, but given how many languages I blog about, it&#39;ll probably need at least highlighting support for a few more). The cells&#39; language and type impacts the evaluation approach we take on the back end, as well as which exports it appears in, and in what form. Specifically, &lt;code&gt;common-lisp/markup&lt;/code&gt; cells are evaluated as &lt;code&gt;:cl-who&lt;/code&gt; forms, don&#39;t appear in &lt;code&gt;.lisp&lt;/code&gt; exports and only contribute their results to an &lt;code&gt;.html&lt;/code&gt; export. By contrast &lt;code&gt;common-lisp/code&lt;/code&gt; is straight up evaluated (capturing warnings, errors and standard-output), contribute their contents to &lt;code&gt;.lisp&lt;/code&gt; exports, and both their contents and results to &lt;code&gt;.html&lt;/code&gt; exports.&lt;/p&gt;&lt;p&gt;In addition to a type, language and id, a cell has a &lt;code&gt;contents&lt;/code&gt;, &lt;code&gt;result&lt;/code&gt;, and a &lt;code&gt;noise&lt;/code&gt;. The contents is what the user has typed in, the result is what that contents evaluates to and the noise dictates how the results are displayed. This is a &lt;code&gt;normal&lt;/code&gt; cell:&lt;/p&gt;&lt;pre class=&quot;cm-s-default&quot;&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;cm-string-2&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;Testing &quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;cm-string-2&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;testing&quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;cm-string-2&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;. One two.~%&quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;cm-string-2&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;Testing.&quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;p onclick=&quot;selectContents(event, this)&quot; class=&quot;stdout&quot;&gt;Testing testing. One two.
Testing.&lt;/p&gt;&lt;span onclick=&quot;selectContents(event, this)&quot; class=&quot;warnings&quot;&gt;&lt;/span&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: integer&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/pre&gt;&lt;p&gt;This is the same cell with a &lt;code&gt;noise&lt;/code&gt; of &lt;code&gt;verbose&lt;/code&gt;: &lt;/p&gt;&lt;pre class=&quot;cm-s-default&quot;&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;cm-string-2&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;Testing &quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;cm-string-2&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;testing&quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;cm-string-2&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;. One two.~%&quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;cm-string-2&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;Testing.&quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: integer&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: integer&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p onclick=&quot;selectContents(event, this)&quot; class=&quot;stdout&quot;&gt;Testing &lt;/p&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;NIL&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: null&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: integer&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p onclick=&quot;selectContents(event, this)&quot; class=&quot;stdout&quot;&gt;testing&lt;/p&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;NIL&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: null&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p onclick=&quot;selectContents(event, this)&quot; class=&quot;stdout&quot;&gt;. One two.
&lt;/p&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;NIL&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: null&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p onclick=&quot;selectContents(event, this)&quot; class=&quot;stdout&quot;&gt;Testing.&lt;/p&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;NIL&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: null&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: integer&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/pre&gt;&lt;p&gt;And again with &lt;code&gt;terse&lt;/code&gt;&lt;/p&gt;&lt;pre class=&quot;cm-s-default&quot;&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;cm-string-2&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;Testing &quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;cm-string-2&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;testing&quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;cm-string-2&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;. One two.~%&quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;cm-string-2&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;Testing.&quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;cm-number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: integer&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/pre&gt;&lt;p&gt;There&#39;s also a &lt;code&gt;silent&lt;/code&gt; setting which lets you ignore the evaluation result entirely.&lt;/p&gt;&lt;p&gt;You can edit a cell (changing its contents), evaluate it (changing its result) delete it, change any of its mentioned properties, or change the order of cells in a notebook. Each of these is an event that gets initiated by a &lt;code&gt;POST&lt;/code&gt; request and gets completed with an  &lt;code&gt;event-stream&lt;/code&gt; message to any listening front-ends (which means I&#39;ll relatively easily be able to make this a multi-user editor when I get to that point). Enough low level stuff, here&#39;s an example.&lt;/p&gt;&lt;h3&gt;Example&lt;/h3&gt;&lt;p&gt;This is a piece of code I actually wrote using &lt;code&gt;cl-notebook&lt;/code&gt;.&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;A parameter is a thing that starts with &lt;code&gt;#-&lt;/code&gt;. It might be nullary or unary. A parameter followed by a parameter or an empty list is interpreted as nullary. A parameter followed by a non-parameter is unary. Command line args are more complicated in the general case, but not in &lt;code&gt;cl-notebook&lt;/code&gt;&lt;/p&gt;&lt;pre class=&quot;cm-s-default&quot;&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-def&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;parse-args!&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;pop&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-def&quot;&gt;flet&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;param?&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;eql&lt;/span&gt; &lt;span class=&quot;cm-error&quot;&gt;#\&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;first-char&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;-&amp;gt;param&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;intern&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;string-upcase&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;string-left-trim&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;-&quot;&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-keyword&quot;&gt;:keyword&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;-&amp;gt;arg&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;parse-integer&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;cm-keyword&quot;&gt;:junk-allowed&lt;/span&gt; &lt;span class=&quot;cm-string-2&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-builtin&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;cm-builtin&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;pop&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;next&lt;/span&gt;
            &lt;span class=&quot;cm-variable&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;param?&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;param?&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;car&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;cm-variable&quot;&gt;collect&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;cons&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;-&amp;gt;param&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-string-2&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;into&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;params&lt;/span&gt;
            &lt;span class=&quot;cm-variable&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;param?&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;cm-variable&quot;&gt;collect&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;cons&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;-&amp;gt;param&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;-&amp;gt;arg&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;pop&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;into&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;params&lt;/span&gt;
            &lt;span class=&quot;cm-variable&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;collect&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;into&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;args&lt;/span&gt;
            &lt;span class=&quot;cm-variable&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;values&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-def&quot;&gt;defun&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;get-param&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;names&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; 
  &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-builtin&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;cm-builtin&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;a&lt;/span&gt; . &lt;span class=&quot;cm-variable&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-builtin&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;params&lt;/span&gt; 
     &lt;span class=&quot;cm-variable&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;member&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-builtin&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;cm-variable&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;GET-PARAM&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: symbol&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/pre&gt;&lt;pre class=&quot;cm-s-default&quot;&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;parse-args!&lt;/span&gt; &lt;span class=&quot;cm-atom&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-string&quot;&gt;&quot;./prog-name&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;-f&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;-h&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;something&quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;parse-args!&lt;/span&gt; &lt;span class=&quot;cm-atom&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-string&quot;&gt;&quot;./prog-name&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;a&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;b&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;c&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;d&quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;parse-args!&lt;/span&gt; &lt;span class=&quot;cm-atom&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-string&quot;&gt;&quot;./prog-name&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;-p&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;4040&quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;get-param&lt;/span&gt; &lt;span class=&quot;cm-atom&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-keyword&quot;&gt;:f&lt;/span&gt; &lt;span class=&quot;cm-keyword&quot;&gt;:force&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;parse-args!&lt;/span&gt; &lt;span class=&quot;cm-atom&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-string&quot;&gt;&quot;./prog-name&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;-f&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;-h&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;something&quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;get-param&lt;/span&gt; &lt;span class=&quot;cm-atom&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-keyword&quot;&gt;:p&lt;/span&gt; &lt;span class=&quot;cm-keyword&quot;&gt;:port&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;parse-args!&lt;/span&gt; &lt;span class=&quot;cm-atom&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-string&quot;&gt;&quot;./prog-name&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;-p&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;4040&quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;get-param&lt;/span&gt; &lt;span class=&quot;cm-atom&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-keyword&quot;&gt;:p&lt;/span&gt; &lt;span class=&quot;cm-keyword&quot;&gt;:port&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;parse-args!&lt;/span&gt; &lt;span class=&quot;cm-atom&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-string&quot;&gt;&quot;./prog-name&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;--port&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;4040&quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;get-param&lt;/span&gt; &lt;span class=&quot;cm-atom&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-keyword&quot;&gt;:p&lt;/span&gt; &lt;span class=&quot;cm-keyword&quot;&gt;:port&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-variable&quot;&gt;parse-args!&lt;/span&gt; &lt;span class=&quot;cm-atom&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm-string&quot;&gt;&quot;./prog-name&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;--frob&quot;&lt;/span&gt; &lt;span class=&quot;cm-string&quot;&gt;&quot;4040&quot;&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;cm-bracket&quot;&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;((:F . T) (:H . &quot;something&quot;))&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: cons&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;NIL&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: null&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;NIL&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: null&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;(&quot;a&quot; &quot;b&quot; &quot;c&quot; &quot;d&quot;)&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: cons&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;((:P . 4040))&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: cons&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;NIL&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: null&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: boolean&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;4040&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: integer&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;4040&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: integer&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul onclick=&quot;selectContents(event, this)&quot; class=&quot;result&quot;&gt;&lt;li&gt;&lt;span class=&quot;value&quot;&gt;NIL&lt;/span&gt;&lt;span class=&quot;type&quot;&gt; :: null&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/pre&gt;&lt;hr /&gt;&lt;p&gt;It&#39;s a small utility function for parsing command line arguments in &lt;code&gt;:cl-notebook&lt;/code&gt;. You can see all the relevant features on display there; it starts with some documentation prose in a &lt;code&gt;markup&lt;/code&gt; cell, has definitions in a &lt;code&gt;code&lt;/code&gt; cell, and finally a bunch of example invocations of each thing in a &lt;code&gt;tests&lt;/code&gt; cell. They&#39;re not &lt;i&gt;really&lt;/i&gt; tests, because they don&#39;t encode my assumptions about the return values of those calls, but you could imagine them doing so. The point is, they won&#39;t be part of a &lt;code&gt;.lisp&lt;/code&gt; export, but &lt;i&gt;will&lt;/i&gt; show up in an &lt;code&gt;html&lt;/code&gt; export like this one.&lt;/p&gt;&lt;p&gt;That&#39;s it for the introductory thoughts. I&#39;ll try to gather some insights into such editors into the next piece I put together. And I&#39;ll continue dogfooding until it gets good enough to call &quot;delicious&quot;.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/2302976596171947107/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2014/04/cl-notebook-introductory-thoughts.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/2302976596171947107'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/2302976596171947107'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2014/04/cl-notebook-introductory-thoughts.html' title='cl-notebook Introductory Thoughts'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-401478029153268483</id><published>2014-04-12T19:10:00.000-07:00</published><updated>2014-04-12T19:14:46.889-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Almost Literate Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="Common Lisp"/><category scheme="http://www.blogger.com/atom/ns#" term="Databases"/><title type='text'>Querying Fact Bases Redux</title><content type='html'>&lt;p&gt;So I &lt;a href=&quot;https://github.com/Inaimathi/fact-base/blob/b2d1dd7e9ecf0e62d8a10d30dfec7570cdfdae04/unify.lisp&quot;&gt;put together&lt;/a&gt; that thing I talked about &lt;a href=&quot;http://langnostic.blogspot.ca/2014/04/querying-fact-bases.html&quot;&gt;last time&lt;/a&gt;, only to discover three things.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Firstly&lt;/b&gt;, the only places I actually needed lazy operation could be handled by passing a body directly to the query macro.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Secondly&lt;/b&gt;, when I loaded the thing up, worked up a 40k fact corpus&lt;a href=&quot;#foot-Sat-Apr-12-205143EDT-2014&quot; name=&quot;note-Sat-Apr-12-205143EDT-2014&quot;&gt;[1]&lt;/a&gt; and ran&lt;/p&gt;

&lt;pre&gt;(for-all (and (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:user&lt;/span&gt; ?name) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:time&lt;/span&gt; ?time) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:number&lt;/span&gt; 62))
         &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; *base* &lt;span style=&quot;color: #483d8b;&quot;&gt;:get&lt;/span&gt; (list ?id ?time ?name))&lt;/pre&gt;

&lt;p&gt;I&#39;d get this:&lt;/p&gt;

&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZCJnEZKjM2Iz9Nl0FRZw1Asvc7-Ycktevd-vCBflxT7r8GFg5i1l3ACyGn2KmiqSw9fkVhbwYVrJP9aTa_o_xvBJTBBl7Oej3wYBg7REjI4CaihFQaZNW9PNiocJfCY9swXt4XQoMWv_P/s1600/slime-eval-screen.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZCJnEZKjM2Iz9Nl0FRZw1Asvc7-Ycktevd-vCBflxT7r8GFg5i1l3ACyGn2KmiqSw9fkVhbwYVrJP9aTa_o_xvBJTBBl7Oej3wYBg7REjI4CaihFQaZNW9PNiocJfCY9swXt4XQoMWv_P/s400/slime-eval-screen.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;You may have noticed that this &lt;i&gt;isn&#39;t&lt;/i&gt; an animated gif. It hangs there for something on the order of thirty seconds, more if profiling is on, and then returns the expected result. So that won&#39;t really do. There&#39;s some interesting points I&#39;ll talk about later, that have to do with clause order and the underlying operations. But, even though this is probably the worst way to write this particular query, it should return in under a second.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Thirdly&lt;/b&gt;, that I had exactly zero use cases for &lt;code&gt;or&lt;/code&gt; goals. This might change, but until then, it looks like I don&#39;t even need unification&lt;a href=&quot;#foot-Sat-Apr-12-205435EDT-2014&quot; name=&quot;note-Sat-Apr-12-205435EDT-2014&quot;&gt;[2]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So as a result, I sat down and took the precise opposite approach to traversal that I tried last time. Instead of trying to keep it elegant and lazy, lets make it hacky and eager. Here&#39;s our problem, once again:&lt;/p&gt;

&lt;pre&gt;(for-all (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:user&lt;/span&gt; ?name) 
         &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; *base* &lt;span style=&quot;color: #483d8b;&quot;&gt;:get&lt;/span&gt; (list ?id ?name))&lt;/pre&gt;

&lt;p&gt;should basically be the same as&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for (a b c) in (current *base*) when (eq b &lt;span style=&quot;color: #483d8b;&quot;&gt;:user&lt;/span&gt;) collect (list a c))&lt;/pre&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;pre&gt;(for-all (and (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:user&lt;/span&gt; ?name) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:time&lt;/span&gt; ?time) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:number&lt;/span&gt; 62) 
         &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; *base* &lt;span style=&quot;color: #483d8b;&quot;&gt;:get&lt;/span&gt; ?time))&lt;/pre&gt;

&lt;p&gt;should more or less be equivalent to&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for (a b c) in (current *base*) 
   when (eq b &lt;span style=&quot;color: #483d8b;&quot;&gt;:user&lt;/span&gt;)
   append (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for (d e f) in (current *base*)
             when (and (eq d a) (eq e &lt;span style=&quot;color: #483d8b;&quot;&gt;:time&lt;/span&gt;)))
             append (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for (g h i) in (current *base*)
                       when (and (eq g d) (eq h &lt;span style=&quot;color: #483d8b;&quot;&gt;:number&lt;/span&gt;) (= i 62))
                       collect f))&lt;/pre&gt;

&lt;p&gt;Except, you know, it should be smarter about using indices where it can. But that&#39;s a pretty straight-forward specification.&lt;/p&gt;

&lt;h3&gt;&lt;code&gt;lookup&lt;/code&gt; and &lt;code&gt;decide-index&lt;/code&gt; changes - take 1&lt;/h3&gt;

&lt;p&gt;The first thing I had to do was change &lt;code&gt;lookup&lt;/code&gt; and &lt;code&gt;decide-index&lt;/code&gt; a bit, because I wanted them to be mildly less naive. And yeah, I broke down and added some macrology to pull out all the repetition in the index-related functions. Turns out that was a good thing.&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmacro&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;lookup-index&lt;/span&gt; (state &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;rest&lt;/span&gt; indices)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;with-gensyms&lt;/span&gt; (st)
    `(&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((,st ,state))
       (&lt;span style=&quot;color: #a020f0;&quot;&gt;cond&lt;/span&gt; ,@(&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for i in indices 
                  for syms = (key-&amp;gt;symbols i)
                  collect `((and (indexed? (index ,st) ,i)
                                 ,@syms)
                            (list ,i ,@syms)))))))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;decide-index&lt;/span&gt; ((state fact-base) &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;optional&lt;/span&gt; a b c)
  (lookup-index state &lt;span style=&quot;color: #483d8b;&quot;&gt;:abc&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:ab&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:ac&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:bc&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:a&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:b&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:c&lt;/span&gt;))&lt;/pre&gt;

&lt;p&gt;Short version is, the function now takes a &lt;code&gt;fact-base&lt;/code&gt; in addition to an &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt; and &lt;code&gt;c&lt;/code&gt;, and checks whether a particular type of index is kept for a fact base before otherwise seeing whether it would be appropriate for the current query.&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;lookup&lt;/span&gt; ((state fact-base) &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;key&lt;/span&gt; a b c)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; (every #&#39;not (list a b c))
      (current state)
      (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((ix (aif (decide-index state a b c)
                     (gethash (rest it) (gethash (first it) (table (index state))))
                     (current state))))
        (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for f in ix
           when (and (or (not a) (equal a (first f)))
                     (or (not b) (equal b (second f)))
                     (or (not c) (equal c (third f))))
           collect f))))&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;lookup&lt;/code&gt; now has to be mindful of this, and has to check that the indexed facts match the incoming query. Because we&#39;re now potentially using a more general index than the query calls for. My gut tells me this is still a net increase in performance since last time, even though our best case is now &lt;code&gt;On&lt;/code&gt; with the size of the result rather than &lt;code&gt;01&lt;/code&gt;. If it comes to it, I&#39;ll go back and make that more efficient.&lt;/p&gt;

&lt;p&gt;Actually, lets fix it right now.&lt;/p&gt;

&lt;h3&gt;&lt;code&gt;lookup&lt;/code&gt; and &lt;code&gt;decide-index&lt;/code&gt; changes - take 2&lt;/h3&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;lookup&lt;/span&gt; ((state fact-base) &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;key&lt;/span&gt; a b c)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; (every #&#39;not (list a b c))
      (current state)
      (&lt;span style=&quot;color: #a020f0;&quot;&gt;multiple-value-bind&lt;/span&gt; (index ideal-index) (decide-index state a b c)
        (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((ix (&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; index
                      (gethash (rest index) (gethash (first index) (table (index state))))
                      (current state))))
          (&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; (and index (eq (first index) ideal-index))
              ix
              (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for f in ix
                 when (and (or (not a) (equal a (first f)))
                           (or (not b) (equal b (second f)))
                           (or (not c) (equal c (third f))))
                 collect f))))))&lt;/pre&gt;

&lt;p&gt;That more complicated version of lookup expects two values instead of one; which &lt;code&gt;index&lt;/code&gt; we&#39;re using, and which &lt;code&gt;index&lt;/code&gt; we&#39;d ideally use. If the two are the same, we just return the results of our lookup, otherwise we have to do the narrowing traversal. That&#39;s about as efficient as it&#39;s going to get without making it lazy. Which I guess I could, but not right now. However, we also need a modified &lt;code&gt;decide-index&lt;/code&gt; to pull this little trick off. And that&#39;s going to be fugly.&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmacro&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;lookup-index&lt;/span&gt; (state &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;rest&lt;/span&gt; indices)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;with-gensyms&lt;/span&gt; (ix ideal applicable?)
    `(&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((,ix (index ,state))
           (,ideal))
       ,@(&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for i in indices 
            for syms = (key-&amp;gt;symbols i)
            collect `(&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((,applicable? (and ,@syms)))
                       (&lt;span style=&quot;color: #a020f0;&quot;&gt;when&lt;/span&gt; (and (null ,ideal) ,applicable?) (setf ,ideal ,i))
                       (&lt;span style=&quot;color: #a020f0;&quot;&gt;when&lt;/span&gt; (and (indexed? ,ix ,i) ,applicable?)
                         (&lt;span style=&quot;color: #a020f0;&quot;&gt;return-from&lt;/span&gt; decide-index 
                           (values (list ,i ,@syms) ,ideal)))))
       (values nil ,ideal))))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;decide-index&lt;/span&gt; ((state fact-base) &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;optional&lt;/span&gt; a b c)
  (lookup-index state &lt;span style=&quot;color: #483d8b;&quot;&gt;:abc&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:ab&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:ac&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:bc&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:a&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:b&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:c&lt;/span&gt;))&lt;/pre&gt;

&lt;p&gt;Say what you will about imperative programming; it&#39;s efficient. That&#39;s a single pass over the relevant indices that returns both the least general applicable index, and the ideal index for a given query. Which means we can now profitably compare the two in &lt;code&gt;lookup&lt;/code&gt;, which means that our best case is back up to &lt;code&gt;O1&lt;/code&gt;, since we don&#39;t need to traverse queries for things we&#39;ve indexed.&lt;/p&gt;

&lt;p&gt;With those modifications, I can pull some fancier crap in translating &lt;code&gt;for-all&lt;/code&gt; calls into &lt;code&gt;loop&lt;/code&gt;s. Specifically, I can do this:&lt;/p&gt;

&lt;h3&gt;This&lt;/h3&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;goal-&amp;gt;destructuring-form&lt;/span&gt; (goal &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;key&lt;/span&gt; (bindings (make-hash-table)))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;labels&lt;/span&gt; ((rec (elem)
             (&lt;span style=&quot;color: #a020f0;&quot;&gt;cond&lt;/span&gt; ((listp elem)
                    (mapcar #&#39;rec elem))
                   ((or (eq &#39;? elem) (not (variable? elem)))
                    (gensym))
                   ((and (variable? elem) (gethash elem bindings))
                    (gensym))
                   ((variable? elem)
                    (setf (gethash elem bindings) t)
                    elem)
                   (t (&lt;span style=&quot;color: #ff0000; font-weight: bold;&quot;&gt;error&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Somethings&#39; up. goal-&amp;gt;destructuring-form~%     ~s~%     ~s~%     ~s&quot;&lt;/span&gt;
                             bindings goal elem)))))
    (mapcar #&#39;rec goal)))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;goal-&amp;gt;lookup&lt;/span&gt; (base goal &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;key&lt;/span&gt; (bindings (make-hash-table)))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;flet&lt;/span&gt; ((-&amp;gt;ix (elem)
           (&lt;span style=&quot;color: #a020f0;&quot;&gt;cond&lt;/span&gt; ((and (variable? elem) (gethash elem bindings))
                  elem)
                 ((any-variables? elem)
                  nil)
                 (t elem))))
    (&lt;span style=&quot;color: #a020f0;&quot;&gt;destructuring-bind&lt;/span&gt; (a b c) goal
      `(lookup ,base 
               &lt;span style=&quot;color: #483d8b;&quot;&gt;:a&lt;/span&gt; ,(-&amp;gt;ix a) 
               &lt;span style=&quot;color: #483d8b;&quot;&gt;:b&lt;/span&gt; ,(-&amp;gt;ix b)
               &lt;span style=&quot;color: #483d8b;&quot;&gt;:c&lt;/span&gt; ,(-&amp;gt;ix c)))))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;goal-&amp;gt;or-expression&lt;/span&gt; (a b c goal)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;flet&lt;/span&gt; ((test (term elem) `(equal ,term ,elem)))
    `(and ,(test a (first goal))
          ,(test b (second goal))
          ,(test c (third goal)))))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;handle-goals&lt;/span&gt; ((goal-type (eql &#39;and)) base goals collecting)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((bindings (make-hash-table)))
    (&lt;span style=&quot;color: #a020f0;&quot;&gt;labels&lt;/span&gt; ((single-goal (destruct lookup tail)
               `(&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for ,destruct in ,lookup ,@tail))
             (rec (goals)
               &lt;span style=&quot;color: #b22222;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;We want to generate the lookups first, 
               ;; because the bindings are going to be generated
               ;; from the result of the lookup. Meaning, if the bindings 
               ;; are established in a given destruct clause,
               ;; they won&#39;t be usable until the NEXT lookup.
               ;; Therefore, even though it isn&#39;t immediately obvious, 
               ;; order matters in this let* form
&lt;/span&gt;
               (&lt;span style=&quot;color: #a020f0;&quot;&gt;let*&lt;/span&gt; ((lookup (goal-&amp;gt;lookup base (first goals) &lt;span style=&quot;color: #483d8b;&quot;&gt;:bindings&lt;/span&gt; bindings))
                      (destruct (goal-&amp;gt;destructuring-form (first goals) &lt;span style=&quot;color: #483d8b;&quot;&gt;:bindings&lt;/span&gt; bindings)))
                 (&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; (null (cdr goals))
                     (single-goal destruct lookup `(collect ,collecting))
                     (single-goal destruct lookup `(append ,(rec (rest goals))))))))
      (rec (rest goals)))))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;handle-goals&lt;/span&gt; (goal-type base goals collecting)
  &lt;span style=&quot;color: #b22222;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;Same story here as in handle-goals (eql &#39;and) method
&lt;/span&gt;  (&lt;span style=&quot;color: #a020f0;&quot;&gt;let*&lt;/span&gt; ((bindings (make-hash-table))
         (lookup (goal-&amp;gt;lookup base goals &lt;span style=&quot;color: #483d8b;&quot;&gt;:bindings&lt;/span&gt; bindings))
         (destruct (goal-&amp;gt;destructuring-form goals &lt;span style=&quot;color: #483d8b;&quot;&gt;:bindings&lt;/span&gt; bindings)))
    `(&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for ,destruct in ,lookup collect ,collecting)))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmacro&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;for-all&lt;/span&gt; (goal-term &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;key&lt;/span&gt; in get)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;with-gensyms&lt;/span&gt; (base)
    (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((template (replace-anonymous (or get `(list ,@(variables-in goal-term))))))
      `(&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((,base ,in))
         ,(handle-goals (first goal-term) base goal-term template)))))&lt;/pre&gt;

&lt;p&gt;We&#39;ll go through it in a minute, but the point of these changes is that writing&lt;/p&gt;

&lt;pre&gt;(for-all (and (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:user&lt;/span&gt; ?name) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:time&lt;/span&gt; ?time) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:number&lt;/span&gt; 62))
         &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; *base* &lt;span style=&quot;color: #483d8b;&quot;&gt;:get&lt;/span&gt; (list ?id ?time ?name))&lt;/pre&gt;

&lt;p&gt;should expand directly into something like&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;LET&lt;/span&gt; ((#&lt;span style=&quot;color: #483d8b;&quot;&gt;:BASE1122&lt;/span&gt; *BASE*))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;LOOP&lt;/span&gt; FOR (?ID #&lt;span style=&quot;color: #483d8b;&quot;&gt;:G1123&lt;/span&gt; ?NAME) 
     IN (LOOKUP #&lt;span style=&quot;color: #483d8b;&quot;&gt;:BASE1122&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:A&lt;/span&gt; NIL &lt;span style=&quot;color: #483d8b;&quot;&gt;:B&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:USER&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:C&lt;/span&gt; NIL)
     APPEND (&lt;span style=&quot;color: #a020f0;&quot;&gt;LOOP&lt;/span&gt; FOR (#&lt;span style=&quot;color: #483d8b;&quot;&gt;:G1124&lt;/span&gt; #&lt;span style=&quot;color: #483d8b;&quot;&gt;:G1125&lt;/span&gt; ?TIME) 
               IN (LOOKUP #&lt;span style=&quot;color: #483d8b;&quot;&gt;:BASE1122&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:A&lt;/span&gt; ?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:B&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:TIME&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:C&lt;/span&gt; NIL)
               APPEND (&lt;span style=&quot;color: #a020f0;&quot;&gt;LOOP&lt;/span&gt; FOR (#&lt;span style=&quot;color: #483d8b;&quot;&gt;:G1126&lt;/span&gt; #&lt;span style=&quot;color: #483d8b;&quot;&gt;:G1127&lt;/span&gt; #&lt;span style=&quot;color: #483d8b;&quot;&gt;:G1128&lt;/span&gt;) 
                         IN (LOOKUP #&lt;span style=&quot;color: #483d8b;&quot;&gt;:BASE1122&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:A&lt;/span&gt; ?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:B&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:NUMBER&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:C&lt;/span&gt; 62)
                         COLLECT (LIST ?ID ?TIME ?NAME)))))&lt;/pre&gt;

&lt;p&gt;rather than the lazy-ish generator tree from last time. Thanks to our re-structuring of &lt;code&gt;lookup&lt;/code&gt;, this is about as efficient as it&#39;s going to get without re-jigging goal order. The only edge case we have is what happens if the entire goal is perfectly indexable, except it seems that the programmer would use &lt;code&gt;lookup&lt;/code&gt; directly in those situations&lt;a href=&quot;#foot-Sat-Apr-12-205517EDT-2014&quot; name=&quot;note-Sat-Apr-12-205517EDT-2014&quot;&gt;[3]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On to the code review. Reading. Whatever.&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;goal-&amp;gt;destructuring-form&lt;/span&gt; (goal &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;key&lt;/span&gt; (bindings (make-hash-table)))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;labels&lt;/span&gt; ((rec (elem)
             (&lt;span style=&quot;color: #a020f0;&quot;&gt;cond&lt;/span&gt; ((listp elem)
                    (mapcar #&#39;rec elem))
                   ((or (eq &#39;? elem) (not (variable? elem)))
                    (gensym))
                   ((and (variable? elem) (gethash elem bindings))
                    (gensym))
                   ((variable? elem)
                    (setf (gethash elem bindings) t)
                    elem)
                   (t (&lt;span style=&quot;color: #ff0000; font-weight: bold;&quot;&gt;error&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Somethings&#39; up. goal-&amp;gt;destructuring-form~%     ~s~%     ~s~%     ~s&quot;&lt;/span&gt;
                             bindings goal elem)))))
    (mapcar #&#39;rec goal)))&lt;/pre&gt;

&lt;p&gt;step one of the transformation is to put together the &lt;code&gt;destructuring-form&lt;/code&gt; for a particular goal&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;;             &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;this thing
&lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;;          &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;vvvvvvvvvvvvvvvvvvv
&lt;/span&gt;  (&lt;span style=&quot;color: #a020f0;&quot;&gt;LOOP&lt;/span&gt; FOR (?ID #&lt;span style=&quot;color: #483d8b;&quot;&gt;:G1123&lt;/span&gt; ?NAME) IN (LOOKUP #&lt;span style=&quot;color: #483d8b;&quot;&gt;:BASE1122&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:A&lt;/span&gt; NIL &lt;span style=&quot;color: #483d8b;&quot;&gt;:B&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:USER&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:C&lt;/span&gt; NIL)
...&lt;/pre&gt;

&lt;p&gt;In order to do that, we have to replace everything &lt;i&gt;other&lt;/i&gt; than variables with &lt;code&gt;gensym&lt;/code&gt; calls, but keep the same tree structure. &lt;code&gt;loop&lt;/code&gt; does deep destructuring, so we can get away with using this as a pattern-matching strategy. We also need to replace already bound variables from previous &lt;code&gt;destructuring-form&lt;/code&gt;s with the same &lt;code&gt;gensym&lt;/code&gt; calls so they don&#39;t get re-assigned unnecessarily.&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;goal-&amp;gt;lookup&lt;/span&gt; (base goal &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;key&lt;/span&gt; (bindings (make-hash-table)))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;flet&lt;/span&gt; ((-&amp;gt;ix (elem)
           (&lt;span style=&quot;color: #a020f0;&quot;&gt;cond&lt;/span&gt; ((and (variable? elem) (gethash elem bindings))
                  elem)
                 ((any-variables? elem)
                  nil)
                 (t elem))))
    (&lt;span style=&quot;color: #a020f0;&quot;&gt;destructuring-bind&lt;/span&gt; (a b c) goal
      `(lookup ,base 
               &lt;span style=&quot;color: #483d8b;&quot;&gt;:a&lt;/span&gt; ,(-&amp;gt;ix a) 
               &lt;span style=&quot;color: #483d8b;&quot;&gt;:b&lt;/span&gt; ,(-&amp;gt;ix b)
               &lt;span style=&quot;color: #483d8b;&quot;&gt;:c&lt;/span&gt; ,(-&amp;gt;ix c)))))&lt;/pre&gt;

&lt;p&gt;The next thing we need to put together is a given goals&#39; &lt;code&gt;lookup&lt;/code&gt; clause&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;;                                       &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;this thing
&lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;;                                 &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
&lt;/span&gt;  (&lt;span style=&quot;color: #a020f0;&quot;&gt;LOOP&lt;/span&gt; FOR (?ID #&lt;span style=&quot;color: #483d8b;&quot;&gt;:G1123&lt;/span&gt; ?NAME) IN (LOOKUP #&lt;span style=&quot;color: #483d8b;&quot;&gt;:BASE1122&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:A&lt;/span&gt; NIL &lt;span style=&quot;color: #483d8b;&quot;&gt;:B&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:USER&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:C&lt;/span&gt; NIL)
...&lt;/pre&gt;

&lt;p&gt;We&#39;re being conservative at the moment, but there&#39;s an optimization or two I could still make here. The way we&#39;re dealing with these is:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;if a given goal-component is a variable, then look it up by its value in the current bindings&lt;a href=&quot;#foot-Sat-Apr-12-205533EDT-2014&quot; name=&quot;note-Sat-Apr-12-205533EDT-2014&quot;&gt;[4]&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;if a given goal-component is a compound form which &lt;i&gt;contains&lt;/i&gt; any variables, don&#39;t index by it&lt;a href=&quot;#foot-Sat-Apr-12-205537EDT-2014&quot; name=&quot;note-Sat-Apr-12-205537EDT-2014&quot;&gt;[5]&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;otherwise, use it as an index&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Onwards to &lt;code&gt;handle-goal&lt;/code&gt;; the real meat of this approach. Lets take a look at how we deal with singleton goals first&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;handle-goals&lt;/span&gt; (goal-type base goals collecting)
  &lt;span style=&quot;color: #b22222;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;Same story here as in handle-goals (eql &#39;and) method
&lt;/span&gt;  (&lt;span style=&quot;color: #a020f0;&quot;&gt;let*&lt;/span&gt; ((bindings (make-hash-table))
         (lookup (goal-&amp;gt;lookup base goals &lt;span style=&quot;color: #483d8b;&quot;&gt;:bindings&lt;/span&gt; bindings))
         (destruct (goal-&amp;gt;destructuring-form goals &lt;span style=&quot;color: #483d8b;&quot;&gt;:bindings&lt;/span&gt; bindings)))
    `(&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for ,destruct in ,lookup collect ,collecting)))&lt;/pre&gt;

&lt;p&gt;Easy, right? grab the results of &lt;code&gt;goal-&amp;gt;lookup&lt;/code&gt; and &lt;code&gt;goal-&amp;gt;destructuring-form&lt;/code&gt; and stitch them into a &lt;code&gt;loop&lt;/code&gt; along with the &lt;code&gt;collecting&lt;/code&gt; clause. Nothing fancy here, except for that cryptic note about a different method definition.&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;handle-goals&lt;/span&gt; ((goal-type (eql &#39;and)) base goals collecting)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((bindings (make-hash-table)))
    (&lt;span style=&quot;color: #a020f0;&quot;&gt;labels&lt;/span&gt; ((single-goal (destruct lookup tail)
               `(&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for ,destruct in ,lookup ,@tail))
             (rec (goals)
               &lt;span style=&quot;color: #b22222;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;We want to generate the lookups first, 
               ;; because the bindings are going to be generated
               ;; from the result of the lookup. Meaning, if the bindings 
               ;; are established in a given destruct clause,
               ;; they won&#39;t be usable until the NEXT lookup.
               ;; Therefore, even though it isn&#39;t immediately obvious, 
               ;; order matters in this let* form
&lt;/span&gt;               (&lt;span style=&quot;color: #a020f0;&quot;&gt;let*&lt;/span&gt; ((lookup (goal-&amp;gt;lookup base (first goals) &lt;span style=&quot;color: #483d8b;&quot;&gt;:bindings&lt;/span&gt; bindings))
                      (destruct (goal-&amp;gt;destructuring-form (first goals) &lt;span style=&quot;color: #483d8b;&quot;&gt;:bindings&lt;/span&gt; bindings)))
                 (&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; (null (cdr goals))
                     (single-goal destruct lookup `(collect ,collecting))
                     (single-goal destruct lookup `(append ,(rec (rest goals))))))))
      (rec (rest goals)))))&lt;/pre&gt;

&lt;p&gt;And this is the full story&lt;a href=&quot;#foot-Sat-Apr-12-205604EDT-2014&quot; name=&quot;note-Sat-Apr-12-205604EDT-2014&quot;&gt;[6]&lt;/a&gt;. Because of the specific way we want &lt;code&gt;lookup&lt;/code&gt; and &lt;code&gt;destruct&lt;/code&gt; to interact with their containing &lt;code&gt;bindings&lt;/code&gt;, their order matters quite a bit. Play around with the macroexpander if you don&#39;t quite see it from just the definition.&lt;/p&gt;

&lt;p&gt;Anyhow, the way we deal with &lt;code&gt;and&lt;/code&gt; goals is by building up a chain of &lt;code&gt;loop&lt;/code&gt; forms, each one dealing with a single goal while taking the previous goals into account. All but the last one need to &lt;code&gt;append&lt;/code&gt; their results, while the last needs to &lt;code&gt;collect&lt;/code&gt; them. The only part we&#39;ve got left is the now trivial step of putting together the &lt;code&gt;for-all&lt;/code&gt; macro interface to the rest of this compilation pipeline&lt;a href=&quot;#foot-Sat-Apr-12-205609EDT-2014&quot; name=&quot;note-Sat-Apr-12-205609EDT-2014&quot;&gt;[7]&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmacro&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;for-all&lt;/span&gt; (goal-term &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;key&lt;/span&gt; in collecting)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;with-gensyms&lt;/span&gt; (base)
    (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((template (replace-anonymous (or get `(list ,@(variables-in goal-term))))))
      `(&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((,base ,in))
         ,(handle-goals (first goal-term) base goal-term template)))))&lt;/pre&gt;

&lt;p&gt;Tadaah!&lt;/p&gt;

&lt;p&gt;I haven&#39;t yet put together an equivalent facility for the old &lt;code&gt;apply&lt;/code&gt; keyword arg, but because of how we&#39;ve changed up the underlying code processors, &lt;code&gt;collecting&lt;/code&gt; can now trivially handle things like&lt;/p&gt;

&lt;pre&gt;(for-all (and (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:user&lt;/span&gt; ?name) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:time&lt;/span&gt; ?time) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:number&lt;/span&gt; 62))
         &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; *base* &lt;span style=&quot;color: #483d8b;&quot;&gt;:collecting&lt;/span&gt; (list ?name (+ ?id ?time 62)))&lt;/pre&gt;

&lt;p&gt;This concludes the part of this post wherein I talk about implementation details. The rest is just one or two interesting notes about traversals. If you&#39;re getting bored, or tired, this is a pretty good break-point for you.&lt;/p&gt;

&lt;h3&gt;Traversal Notes&lt;/h3&gt;

&lt;p&gt;Near the beginning of this piece, I said&lt;/p&gt;

&lt;blockquote&gt;...this is probably the worst way to write this particular query...&lt;span class=&quot;sig&quot;&gt;-Inaimathi&lt;/span&gt;&lt;/blockquote&gt;

&lt;p&gt;referring to&lt;/p&gt;

&lt;pre&gt;(for-all (and (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:user&lt;/span&gt; ?name) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:time&lt;/span&gt; ?time) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:number&lt;/span&gt; 62))
         &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; *base* &lt;span style=&quot;color: #483d8b;&quot;&gt;:get&lt;/span&gt; (list ?id ?time ?name))&lt;/pre&gt;

&lt;p&gt;and the reason should be fairly obvious now that we know exactly how we go about finding these answers. Remember, the expansion for this form, after compensating for the different keyword argument in our new &lt;code&gt;for-all&lt;/code&gt;, is&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;LET&lt;/span&gt; ((#&lt;span style=&quot;color: #483d8b;&quot;&gt;:BASE1262&lt;/span&gt; *BASE*))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;LOOP&lt;/span&gt; FOR (?ID #&lt;span style=&quot;color: #483d8b;&quot;&gt;:G1263&lt;/span&gt; ?NAME) 
    IN (LOOKUP #&lt;span style=&quot;color: #483d8b;&quot;&gt;:BASE1262&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:A&lt;/span&gt; NIL &lt;span style=&quot;color: #483d8b;&quot;&gt;:B&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:USER&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:C&lt;/span&gt; NIL)
    APPEND (&lt;span style=&quot;color: #a020f0;&quot;&gt;LOOP&lt;/span&gt; FOR (#&lt;span style=&quot;color: #483d8b;&quot;&gt;:G1264&lt;/span&gt; #&lt;span style=&quot;color: #483d8b;&quot;&gt;:G1265&lt;/span&gt; ?TIME) 
              IN (LOOKUP #&lt;span style=&quot;color: #483d8b;&quot;&gt;:BASE1262&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:A&lt;/span&gt; ?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:B&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:TIME&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:C&lt;/span&gt; NIL)
              APPEND (&lt;span style=&quot;color: #a020f0;&quot;&gt;LOOP&lt;/span&gt; FOR (#&lt;span style=&quot;color: #483d8b;&quot;&gt;:G1266&lt;/span&gt; #&lt;span style=&quot;color: #483d8b;&quot;&gt;:G1267&lt;/span&gt; #&lt;span style=&quot;color: #483d8b;&quot;&gt;:G1268&lt;/span&gt;) 
                        IN (LOOKUP #&lt;span style=&quot;color: #483d8b;&quot;&gt;:BASE1262&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:A&lt;/span&gt; ?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:B&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:NUMBER&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:C&lt;/span&gt; 62)
                        COLLECT (LIST ?ID ?TIME ?NAME)))))&lt;/pre&gt;

&lt;p&gt;and just so that we&#39;re perfectly clear on what that means, here&#39;s the Lisp-esque pseudo-code&lt;/p&gt;

&lt;pre&gt;(for-each goal-1
    append (for-each goal-2 
               append (for-each goal-3
                          collect [some list of components])))&lt;/pre&gt;

&lt;p&gt;Now granted, we&#39;re aggressively using indices where we can, so we can slice a lot of the constant time out of this equation depending on how often such an operation happens, but &lt;i&gt;no matter&lt;/i&gt; how efficiently we slice it, we&#39;re going to take a number of steps equal to &lt;code&gt;goal-3 * (goal-2 * goal-1)&lt;/code&gt;. That is, we&#39;re going &lt;code&gt;On&lt;/code&gt; over the candidates for the last goal, for each candidate of the previous goal, for each candidate of the previous goal and so on.&lt;/p&gt;

&lt;p&gt;This is why the indices help us a lot. If we couldn&#39;t effectively discount swathes of our initial corpus, the performance characteristic would be &lt;code&gt;On^m&lt;/code&gt; where &lt;code&gt;n&lt;/code&gt; is the size of our fact base and &lt;code&gt;m&lt;/code&gt; is the number of goals. Meaning that it behooves us to cut as many candidates as early as possible, since early reductions in our problem space will give us much better returns.&lt;/p&gt;

&lt;p&gt;In other words, to paraphrasingly re-iterate Norvig, even though&lt;/p&gt;

&lt;pre&gt;(for-all (and (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:user&lt;/span&gt; ?name) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:time&lt;/span&gt; ?time) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:number&lt;/span&gt; 62))
         &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; *base* &lt;span style=&quot;color: #483d8b;&quot;&gt;:get&lt;/span&gt; (list ?id ?time ?name))&lt;/pre&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;pre&gt;(for-all (and (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:number&lt;/span&gt; 62) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:time&lt;/span&gt; ?time) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:user&lt;/span&gt; ?name))
         &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; *base* &lt;span style=&quot;color: #483d8b;&quot;&gt;:get&lt;/span&gt; (list ?id ?time ?name))&lt;/pre&gt;

&lt;p&gt;are logically equivalent, the latter is going to perform noticeably better, because &lt;code&gt;(?id :number 62)&lt;/code&gt; has a much smaller set of candidate facts than &lt;code&gt;(?id :user ?name)&lt;/code&gt; in our particular corpus. One interesting exercise, which I&#39;ll leave for next time, would be to have &lt;code&gt;for-all&lt;/code&gt; try to optimally sort its &lt;code&gt;and&lt;/code&gt; goals by putting the smallest candidate lists at the beginning so as to reduce the search-space with no thought required from the user. The above is a trivial example; there&#39;s one goal that has more indexable terms in it than the others, so in general&lt;a href=&quot;#foot-Sat-Apr-12-205638EDT-2014&quot; name=&quot;note-Sat-Apr-12-205638EDT-2014&quot;&gt;[8]&lt;/a&gt; it will probably yield a smaller candidate list. The real way about this feels like it would be to aggressively index goals at the start of a query and sample their corpus size, then sort on that. Not sure if that would cost more than it buys me though, since it feels like that would get complex fast.&lt;/p&gt;

&lt;p&gt;Anyway, like I said, I&#39;ll leave it for next time.&lt;/p&gt;

&lt;p&gt;If I end up seeing performance issues in the things I&#39;m building out of &lt;a href=&quot;https://github.com/Inaimathi/fact-base&quot;&gt;&lt;code&gt;fact-base&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And I get bored.&lt;/p&gt;


&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Sat-Apr-12-205143EDT-2014&quot; name=&quot;foot-Sat-Apr-12-205143EDT-2014&quot;&gt;[back]&lt;/a&gt; - Like this, if you&#39;re interested:

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defparameter&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;*base*&lt;/span&gt; (make-fact-base &lt;span style=&quot;color: #483d8b;&quot;&gt;:indices&lt;/span&gt; &#39;(&lt;span style=&quot;color: #483d8b;&quot;&gt;:a&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:ab&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:abc&lt;/span&gt;)))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;test-generate!&lt;/span&gt; (n)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; repeat n
     do (multi-insert! 
         *base* `((&lt;span style=&quot;color: #483d8b;&quot;&gt;:number&lt;/span&gt; ,(random 100)) (&lt;span style=&quot;color: #483d8b;&quot;&gt;:type&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:digit&lt;/span&gt;) 
                  (&lt;span style=&quot;color: #483d8b;&quot;&gt;:time&lt;/span&gt; ,(get-universal-time)) 
                  (&lt;span style=&quot;color: #483d8b;&quot;&gt;:user&lt;/span&gt; ,(nth (random 7) &#39;(&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Anon&quot;&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Someone Else&quot;&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Albert&quot;&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Beatrice&quot;&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Charles&quot;&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Daria&quot;&lt;/span&gt;)))))))

(test-generate! 10000)&lt;/pre&gt;&lt;/p&gt;

&lt;p&gt;2 - &lt;a href=&quot;#note-Sat-Apr-12-205435EDT-2014&quot; name=&quot;foot-Sat-Apr-12-205435EDT-2014&quot;&gt;[back]&lt;/a&gt; - Which makes things much simpler for this approach. Hopefully, you&#39;ll see why as we go.&lt;/p&gt;

&lt;p&gt;3 - &lt;a href=&quot;#note-Sat-Apr-12-205517EDT-2014&quot; name=&quot;foot-Sat-Apr-12-205517EDT-2014&quot;&gt;[back]&lt;/a&gt; - and they can, since it&#39;s still an &lt;code&gt;&lt;span style=&quot;color: #483d8b;&quot;&gt;:export&lt;/span&gt;&lt;/code&gt;ed symbol itself.&lt;/p&gt;

&lt;p&gt;4 - &lt;a href=&quot;#note-Sat-Apr-12-205533EDT-2014&quot; name=&quot;foot-Sat-Apr-12-205533EDT-2014&quot;&gt;[back]&lt;/a&gt; - if it has been bound by a previous &lt;code&gt;destructuring-form&lt;/code&gt;, it&#39;ll be assigned by this point, which means we&#39;ll be able to index by it. Otherwise, &lt;code&gt;gethash&lt;/code&gt; will return &lt;code&gt;nil&lt;/code&gt;, which is exactly what we want.&lt;/p&gt;

&lt;p&gt;5 - &lt;a href=&quot;#note-Sat-Apr-12-205537EDT-2014&quot; name=&quot;foot-Sat-Apr-12-205537EDT-2014&quot;&gt;[back]&lt;/a&gt; - This is where we could be a bit more efficient, in case you&#39;re interested. If we wanted to be very precise about it, we&#39;d say that we &lt;i&gt;could&lt;/i&gt; use a compound form with variables as an index, provided that all of its variables have been bound prior to this point in the traversal. I&#39;m leaving it out for now because 

&lt;ul&gt;
  &lt;li&gt;it would further complicate an already tricky chunk of code &lt;/li&gt;
  &lt;li&gt;I&#39;m not sure how often this edge case would happen in practice and &lt;/li&gt;
  &lt;li&gt;if it &lt;i&gt;does&lt;/i&gt; happen, the current result will be a slightly less efficient traversal, which doesn&#39;t sound too bad. If the consequence were incorrect results instead, I&#39;d have reconsidered&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;

&lt;p&gt;6 - &lt;a href=&quot;#note-Sat-Apr-12-205604EDT-2014&quot; name=&quot;foot-Sat-Apr-12-205604EDT-2014&quot;&gt;[back]&lt;/a&gt; - As an aside, this is the first place I&#39;ve seen in something like 8 years where a comment is appropriate. It doesn&#39;t mirror the code to which it pertains &lt;i&gt;and&lt;/i&gt; it explains a non-obvious but necessary facet of the implementation. Usually, I&#39;d either work out some naming scheme that would make the point obvious, or just factor out the chunk of code that needs explanation. There doesn&#39;t need to be a simple way of doing either here&lt;a href=&quot;#foot-Sat-Apr-12-205721EDT-2014&quot; name=&quot;note-Sat-Apr-12-205721EDT-2014&quot;&gt;[9]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;7 - &lt;a href=&quot;#note-Sat-Apr-12-205609EDT-2014&quot; name=&quot;foot-Sat-Apr-12-205609EDT-2014&quot;&gt;[back]&lt;/a&gt; - And just to highlight this, it &lt;i&gt;is&lt;/i&gt; a compilation pipeline. I mentioned this at a semi-Lisp-related meet-up lately, and it&#39;s true enough to repeat to the internets: a good way of conceptualizing a Common Lisp macro is as a compiler that takes some Lisp code and emits different Lisp code. Because of the way Lisp is structured, we get the first chunk of an actual compilation pipeline for free, and essentially start with a tokenized input. It&#39;s a pretty powerful technique once you get your head around it.&lt;/p&gt;

&lt;p&gt;8 - &lt;a href=&quot;#note-Sat-Apr-12-205638EDT-2014&quot; name=&quot;foot-Sat-Apr-12-205638EDT-2014&quot;&gt;[back]&lt;/a&gt; - Though not necessarily in plenty of specific cases.&lt;/p&gt;

&lt;p&gt;9 - &lt;a href=&quot;#note-Sat-Apr-12-205721EDT-2014&quot; name=&quot;foot-Sat-Apr-12-205721EDT-2014&quot;&gt;[back]&lt;/a&gt; - Though I guess I could factor that let out into a &lt;code&gt;with-for-all-forms&lt;/code&gt; if it turned out I had to repeat it in many places.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/401478029153268483/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2014/04/querying-fact-bases-redux.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/401478029153268483'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/401478029153268483'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2014/04/querying-fact-bases-redux.html' title='Querying Fact Bases Redux'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZCJnEZKjM2Iz9Nl0FRZw1Asvc7-Ycktevd-vCBflxT7r8GFg5i1l3ACyGn2KmiqSw9fkVhbwYVrJP9aTa_o_xvBJTBBl7Oej3wYBg7REjI4CaihFQaZNW9PNiocJfCY9swXt4XQoMWv_P/s72-c/slime-eval-screen.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-5956460889232131318</id><published>2014-04-09T21:01:00.002-07:00</published><updated>2014-05-21T10:19:27.897-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Almost Literate Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="Common Lisp"/><category scheme="http://www.blogger.com/atom/ns#" term="Databases"/><title type='text'>Querying Fact Bases</title><content type='html'>&lt;p&gt;So it seems that a lot of people are into this logic programming thing I&#39;ve been reading about lately. There&#39;s the already mentioned Reasoned Schemer trio of Friedman/Byrd/Kiselyov behind the beautiful but arcane &lt;a href=&quot;http://minikanren.org/&quot;&gt;miniKanren language&lt;/a&gt;, a prolog-like contained in Peter Norvig&#39;s &lt;a href=&quot;http://norvig.com/paip.html&quot;&gt;Paradigms of Artificial Intelligence Programming&lt;/a&gt; chapters 11, 12 and 14, another one in Graham&#39;s &lt;a href=&quot;http://www.paulgraham.com/onlisp.html&quot;&gt;On Lisp&lt;/a&gt; chapters 19, 22, 23, 24 and yet another in &lt;a href=&quot;http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-29.html#%_sec_4.4&quot;&gt;chapter 4.4&lt;/a&gt; of &lt;a href=&quot;http://mitpress.mit.edu/sicp/full-text/book/book.html&quot;&gt;Abelson and Sussman&#39;s SICP&lt;/a&gt;. So there&#39;s a lot of literature around dealing with how you go about building a unifier or pattern-matcher&lt;a href=&quot;#foot-Thu-Apr-10-000043EDT-2014&quot; name=&quot;note-Thu-Apr-10-000043EDT-2014&quot;&gt;[1]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Anyway, I&#39;ve been consuming this literature for a while, and the part I want to zoom in on is searching the database. The other stuff is easy; a unifier can be straight-forwardly built in about ten lines&lt;a href=&quot;#foot-Thu-Apr-10-000046EDT-2014&quot; name=&quot;note-Thu-Apr-10-000046EDT-2014&quot;&gt;[2]&lt;/a&gt; and handling variables is the same tree-traversal stuff you&#39;ve seen a hundred times before, but the actual search never seems to be the focus of these things. And I&#39;m looking for a particular type of search for &lt;a href=&quot;https://github.com/Inaimathi/fact-base&quot;&gt;&lt;code&gt;fact-base&lt;/code&gt;&lt;/a&gt;. I showed it off recently at a &lt;a href=&quot;http://lispwiki.inaimathi.ca/&quot;&gt;Toronto Lisp Group&lt;/a&gt; meeting along with the app it&#39;s supposed to enable and mentioned that querying is mildly annoying when you get to compound queries. Specifically, I took as an example the very simple database&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defparameter&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;base&lt;/span&gt; (make-fact-base))
(insert! base (list 0 &lt;span style=&quot;color: #483d8b;&quot;&gt;:message&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;This is a sample message&quot;&lt;/span&gt;))
(insert! base (list 1 &lt;span style=&quot;color: #483d8b;&quot;&gt;:message&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;This is another one&quot;&lt;/span&gt;))
(insert! base (list 1 &lt;span style=&quot;color: #483d8b;&quot;&gt;:author&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;))
(insert! base (list 2 &lt;span style=&quot;color: #483d8b;&quot;&gt;:message&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;That second one was written by me. This one is a meta-message (also by me).&quot;&lt;/span&gt;))
(insert! base (list 2 &lt;span style=&quot;color: #483d8b;&quot;&gt;:author&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;))
(insert! base (list 2 &lt;span style=&quot;color: #483d8b;&quot;&gt;:type&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:meta&lt;/span&gt;))&lt;/pre&gt;

&lt;p&gt;and pointed out that in order to find &lt;code&gt;All the message bodies authored by Inaimathi&lt;/code&gt;, you&#39;d have to take two steps&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;traverse the database looking for facts that have &lt;code&gt;&#39;(:author &quot;Inaimathi&quot;)&lt;/code&gt; for a &lt;code&gt;rest&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;get all the facts that have the same &lt;code&gt;first&lt;/code&gt; as one of the above and the &lt;code&gt;second&lt;/code&gt; &lt;code&gt;:message&lt;/code&gt;, and collect their &lt;code&gt;third&lt;/code&gt;s&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In actual lisp, that looks like&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for (a b c) in (lookup base &lt;span style=&quot;color: #483d8b;&quot;&gt;:b&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:author&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:c&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) 
      collect (caddar (lookup base &lt;span style=&quot;color: #483d8b;&quot;&gt;:a&lt;/span&gt; a &lt;span style=&quot;color: #483d8b;&quot;&gt;:b&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:message&lt;/span&gt;)))&lt;/pre&gt;

&lt;p&gt;That&#39;s even passably fast, thanks to &lt;a href=&quot;http://langnostic.blogspot.ca/2014/03/fact-base-indices.html&quot;&gt;our &lt;code&gt;index&lt;/code&gt; system&lt;/a&gt;, but it&#39;s annoying to write, and it forces me to do a &lt;code&gt;fact-base-&amp;gt;objects&lt;/code&gt; conversion in some places rather than write out these multi-stage iterations myself. What I&#39;d like to be able to do in the above is something like&lt;/p&gt;

&lt;pre&gt;(for-all (and (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:author&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:message&lt;/span&gt; ?message)) &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; my-fact-base &lt;span style=&quot;color: #483d8b;&quot;&gt;:get&lt;/span&gt; ?message)&lt;/pre&gt;

&lt;p&gt;and have the system figure it out for me. Granted in this situation, you don&#39;t gain very much, but it would be a compounding gain for more complex queries. For instance, if I suddenly decided I want to select &lt;code&gt;All the message bodies authored by Inaimathi pertaining to other messages&lt;/code&gt;, the query language version handles it very simply:&lt;/p&gt;

&lt;pre&gt;(for-all (and (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:author&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:message&lt;/span&gt; ?message) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:type&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:meta&lt;/span&gt;)) &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; my-fact-base &lt;span style=&quot;color: #483d8b;&quot;&gt;:get&lt;/span&gt; ?message)&lt;/pre&gt;

&lt;p&gt;whereas the manual version would add another level of iteration I&#39;d need to work through. Oh, and have fun with the situation where you only want the first 5 or so hits. The easiest solution with the manual approach is searching the entire space and throwing away all but the first &lt;code&gt;n&lt;/code&gt; results. You &lt;i&gt;could&lt;/i&gt; do better, but you&#39;re suddenly in the &lt;i&gt;supremely&lt;/i&gt; annoying situation where your queries all look mildly different, but perform the same basic task.&lt;/p&gt;

&lt;p&gt;What I figure I&#39;d want is a lazy or lazy-ish way of getting the results. The lazy solution can easily be converted to the eager solution later, but it&#39;s really painful to take the eager approach and &lt;i&gt;then&lt;/i&gt; find out that you only needed to do about 4% of the work done. I&#39;ll be using &lt;a href=&quot;http://en.wikipedia.org/wiki/Generator_%28computer_programming%29&quot;&gt;generators&lt;/a&gt;, rather than outright lazy sequences just because they&#39;re mildly easier to put together. For a single goal, that&#39;s trivial.&lt;/p&gt;

&lt;pre&gt;(for-all (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:author&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; my-fact-base)&lt;/pre&gt;

&lt;p&gt;All you have to do here is have a generator that runs over the facts in &lt;code&gt;my-fact-base&lt;/code&gt; and returns the next matching one it finds. Something like&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;match-single&lt;/span&gt; (goal bindings facts)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((fs facts))
    (&lt;span style=&quot;color: #a020f0;&quot;&gt;lambda&lt;/span&gt; ()
      (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for res = (unify goal (pop fs) bindings)
         unless (fail? res) do (&lt;span style=&quot;color: #a020f0;&quot;&gt;return&lt;/span&gt; res)
         while fs
         finally (&lt;span style=&quot;color: #a020f0;&quot;&gt;return&lt;/span&gt; (fail))))))&lt;/pre&gt;

&lt;p&gt;would do fine. I&#39;m pointedly refusing to commit to an implementation of &lt;code&gt;(fail)&lt;/code&gt;, &lt;code&gt;unify&lt;/code&gt; and &lt;code&gt;bindings&lt;/code&gt; at each point for the purposes of this post, but am using the stuff out of &lt;a href=&quot;http://norvig.com/paip/README.html&quot;&gt;Norvig&#39;s PAIP source code&lt;/a&gt;. For the uninitiated: A &lt;code&gt;goal&lt;/code&gt; is the thing you&#39;re trying to match; it&#39;s an expression that may contain some &lt;code&gt;variable&lt;/code&gt;s. A &lt;code&gt;variable&lt;/code&gt; is a thing that you can substitute; it can either be unbound or assigned a value in a particular set of &lt;code&gt;bindings&lt;/code&gt;. If a &lt;code&gt;unification&lt;/code&gt; fails, it returns &lt;code&gt;(fail)&lt;/code&gt;, and if it&#39;s successful it returns the set of &lt;code&gt;bindings&lt;/code&gt; that would make that unification expression true. For instance, if you unified &lt;code&gt;?a&lt;/code&gt; with &lt;code&gt;5&lt;/code&gt;, starting with empty bindings, &lt;code&gt;unify&lt;/code&gt; would return the set of &lt;code&gt;bindings&lt;/code&gt; in which &lt;code&gt;?a&lt;/code&gt; is bound to &lt;code&gt;5&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So the above &lt;code&gt;match-single&lt;/code&gt; definition would return a generator which, when called, would either &lt;code&gt;(fail)&lt;/code&gt;, &lt;i&gt;or&lt;/i&gt; return the environment resulting from &lt;code&gt;unify&lt;/code&gt;ing the next element of &lt;code&gt;facts&lt;/code&gt; with &lt;code&gt;goal&lt;/code&gt;. Hopefully, straight-forward, though you may need to do a bit of reading up on it if you&#39;ve never seen the terms before.&lt;/p&gt;

&lt;p&gt;The next easiest thing to do would be handling a set of &lt;code&gt;or&lt;/code&gt;ed goals. That is&lt;/p&gt;

&lt;pre&gt;(for-all (or (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:author&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Aaron&quot;&lt;/span&gt;) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:author&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Bradley&quot;&lt;/span&gt;)) &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; my-fact-base)&lt;/pre&gt;

&lt;p&gt;It&#39;s basically the same thing, except that instead of applying a single goal and checking if it sticks, we&#39;re applying several goals in sequence and seeing if any of them stick. Something like&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;match-ors&lt;/span&gt; (goals bindings facts)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((fs facts))
    (&lt;span style=&quot;color: #a020f0;&quot;&gt;flet&lt;/span&gt; ((try-goals (f)
             (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for g in goals
                for res = (unify g f bindings)
                when res do (&lt;span style=&quot;color: #a020f0;&quot;&gt;return&lt;/span&gt; res)
                finally (&lt;span style=&quot;color: #a020f0;&quot;&gt;return&lt;/span&gt; (fail)))))
      (&lt;span style=&quot;color: #a020f0;&quot;&gt;lambda&lt;/span&gt; ()
        (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for res = (try-goals (pop fs))
           unless (fail? res) do (&lt;span style=&quot;color: #a020f0;&quot;&gt;return&lt;/span&gt; res)
           while fs
           finally (&lt;span style=&quot;color: #a020f0;&quot;&gt;return&lt;/span&gt; (fail)))))))&lt;/pre&gt;

&lt;p&gt;which is by my estimation only marginally more complicated. The tricky part is traversing a fact-base in order to satisfy &lt;code&gt;and&lt;/code&gt;ed goals. Like in that example I mentioned near the beginning:&lt;/p&gt;

&lt;pre&gt;(for-all (and (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:author&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:message&lt;/span&gt; ?message) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:type&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:meta&lt;/span&gt;)) &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; my-fact-base &lt;span style=&quot;color: #483d8b;&quot;&gt;:get&lt;/span&gt; ?message)&lt;/pre&gt;

&lt;p&gt;Think about it.&lt;/p&gt;

&lt;p&gt;What you want here is fairly complicated to express in English. I&#39;m still trying to return a generator from the whole thing, but expressing its behavior is a complex.&lt;/p&gt;

&lt;p&gt;If you only get one goal, you want to fall through to a call to &lt;code&gt;match-single&lt;/code&gt;; that&#39;s still fairly straight-forward. The magic happens at more than one goal. And I just deleted about four paragraphs of prose that would have thoroughly confused you. It&#39;s not a very easy set of concepts to express in English because it refers to pieces of itself fairly often.&lt;/p&gt;

&lt;p&gt;Lets try it this way:&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;match-ands&lt;/span&gt; (goals bindings facts)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((generator (match-single (first goals) bindings facts))
        (rest-generator))
    (&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; (null (cdr goals))
        generator
        (&lt;span style=&quot;color: #a020f0;&quot;&gt;labels&lt;/span&gt; ((next-gen ()
                   (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((res (funcall generator)))
                     (&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; (fail? res)
                         (fail)
                         (setf rest-generator (match-ands (rest goals) res facts)))))
                 (backtrack! ()
                   (&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; (fail? (next-gen))
                       (fail)
                       (next)))
                 (next ()
                   (&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; (null rest-generator)
                       (backtrack!)
                       (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((res (funcall rest-generator)))
                         (&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; (fail? res)
                             (backtrack!)
                             res)))))
          #&#39;next))))&lt;/pre&gt;

&lt;p&gt;The image you want, once you&#39;ve put the initial generator tower together, is one of those combo bike-locks.&lt;/p&gt;

&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjudHBfk1d39sTYBEz_B4DqC25w4otrmuX3Duo2G0u2b6U7k361XUWcqT4mIJ1EQ93Q6QaQnrKwlMUzU2pNfWSxZIo0Hkjq6mFMxzzTK2-8EgsfXfrp53eJa4wZ4qSY1Dm335z4vcTXR525/s1600/trek-dreadlocks-resettable-combination-cable-lock.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjudHBfk1d39sTYBEz_B4DqC25w4otrmuX3Duo2G0u2b6U7k361XUWcqT4mIJ1EQ93Q6QaQnrKwlMUzU2pNfWSxZIo0Hkjq6mFMxzzTK2-8EgsfXfrp53eJa4wZ4qSY1Dm335z4vcTXR525/s320/trek-dreadlocks-resettable-combination-cable-lock.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;If you want to search its entire possibility space, you spin the last ring until it runs out of values. Then you spin the second-to-last ring once, and retry the last ring. When you run out of values on the second-to-last ring, you spin the third-to-last ring once and so on. It&#39;s an incredibly tedious exercise, which is why I&#39;d prefer a machine to handle it.&lt;/p&gt;

&lt;p&gt;Now, chunk by chunk&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;match-ands&lt;/span&gt; (goals bindings facts)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((generator (match-single (first goals) bindings facts))
        (rest-generator))
    (&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; (null (cdr goals))
        generator
        ...&lt;/pre&gt;

&lt;p&gt;By the time we&#39;re calling this function, I assume that it&#39;ll be handed at least one goal. You always want the generator of your first goal, and if you only get the one goal, you just return said generator and you&#39;re done. Multiple goals are where you need to pull fancy footwork. Again, one chunk at a time:&lt;/p&gt;

&lt;pre&gt;        ...
        (&lt;span style=&quot;color: #a020f0;&quot;&gt;labels&lt;/span&gt; ((next-gen ()
                   (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((res (funcall generator)))
                     (&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; (fail? res)
                         (fail)
                         (setf rest-generator (match-ands (rest goals) res facts)))))
                 ...&lt;/pre&gt;

&lt;p&gt;This is where we set the &lt;code&gt;rest-generator&lt;/code&gt; from earlier. It&#39;s just the procedure that will return the next result from proving the rest of the goals given the set of &lt;code&gt;bindings&lt;/code&gt; built from proving the first goal into the starting set of &lt;code&gt;bindings&lt;/code&gt; given to &lt;code&gt;match-ands&lt;/code&gt; initially. If calling the first goals&#39; generator fails, we likewise fail; otherwise we set &lt;code&gt;rest-generator&lt;/code&gt; to the generator we create by passing the result back up to &lt;code&gt;match-ands&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;                 ...
                 (backtrack! ()
                   (&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; (fail? (next-gen))
                       (fail)
                       (next)))
                 ...&lt;/pre&gt;

&lt;p&gt;Occasionally, we have to backtrack. Which in this context means we try to call &lt;code&gt;next-gen&lt;/code&gt;. If that fails, we likewise fail, otherwise we invoke &lt;code&gt;next&lt;/code&gt;. Which...&lt;/p&gt;

&lt;pre&gt;                 ...
                 (next ()
                   (&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; (null rest-generator)
                       (backtrack!)
                       (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((res (funcall rest-generator)))
                         (&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; (fail? res)
                             (backtrack!)
                             res)))))
                       ...&lt;/pre&gt;

&lt;p&gt;...sets up an initial &lt;code&gt;rest-generator&lt;/code&gt; if there isn&#39;t one, then tries to call it. If that fails, we &lt;code&gt;backtrack!&lt;/code&gt;&lt;a href=&quot;#foot-Thu-Apr-10-000130EDT-2014&quot; name=&quot;note-Thu-Apr-10-000130EDT-2014&quot;&gt;[3]&lt;/a&gt;, otherwise we return the result.&lt;/p&gt;

&lt;pre&gt;          ...
          #&#39;next))))&lt;/pre&gt;

&lt;p&gt;That &lt;code&gt;next&lt;/code&gt; function I just described is the generator we want for a multi-goal proof, which means that it&#39;s the final return value from &lt;code&gt;match-ands&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The only required piece of infrastructure left is &lt;code&gt;for-all&lt;/code&gt; itself. We want it to be able to provide results, or do something with them lazily. Which means it&#39;ll look something like&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmacro&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;for-all&lt;/span&gt; (goal-term &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;key&lt;/span&gt; in get apply)
  (&lt;span style=&quot;color: #ff0000; font-weight: bold;&quot;&gt;assert&lt;/span&gt; in nil &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Need a database to query...&quot;&lt;/span&gt;)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;when&lt;/span&gt; (and get apply)
    (format t &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;:apply and :get arguments passed in; ignoring :get&quot;&lt;/span&gt;))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;with-gensyms&lt;/span&gt; (template gen res facts)
    `(&lt;span style=&quot;color: #a020f0;&quot;&gt;let*&lt;/span&gt; ((,facts ,in)
            (,gen ,(&lt;span style=&quot;color: #a020f0;&quot;&gt;cond&lt;/span&gt; ((eq &#39;and (car goal-term))
                          `(match-ands &#39;,(replace-anonymous (rest goal-term)) +succeed+ ,facts))
                         ((eq &#39;or (car goal-term))
                          `(match-ors &#39;,(replace-anonymous (rest goal-term)) +succeed+ ,facts))
                         (t
                          `(match-single &#39;,goal-term +succeed+ ,facts))))
            ,@(&lt;span style=&quot;color: #a020f0;&quot;&gt;unless&lt;/span&gt; apply
              `((,template &#39;,(replace-anonymous (or get goal-term))))))
       (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for ,res = (funcall ,gen)
          while ,res collect ,(&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; apply
                                  `(apply (&lt;span style=&quot;color: #a020f0;&quot;&gt;lambda&lt;/span&gt; ,(variables-in apply) ,apply)
                                          (subst-bindings ,res &#39;,(variables-in apply)))
                                  `(subst-bindings ,res ,template))))))&lt;/pre&gt;

&lt;p&gt;Which isn&#39;t nearly as complicated as it seems at first glance. Lets go through that too.&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmacro&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;for-all&lt;/span&gt; (goal-term &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;key&lt;/span&gt; in get apply)
  (&lt;span style=&quot;color: #ff0000; font-weight: bold;&quot;&gt;assert&lt;/span&gt; in nil &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Need a database to query...&quot;&lt;/span&gt;)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;when&lt;/span&gt; (and get apply)
    (format t &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;:apply and :get arguments passed in; ignoring :get&quot;&lt;/span&gt;))
    ...&lt;/pre&gt;

&lt;p&gt;arguments, and trying to be helpful with invocation errors. We want the thing to be &lt;i&gt;readable&lt;/i&gt; too, which is why I use &quot;mandatory&quot; keyword arguments in this one.&lt;/p&gt;

&lt;pre&gt;  ...
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;with-gensyms&lt;/span&gt; (template gen res facts)
    `(&lt;span style=&quot;color: #a020f0;&quot;&gt;let*&lt;/span&gt; ((,facts ,in)
            (,gen ,(&lt;span style=&quot;color: #a020f0;&quot;&gt;cond&lt;/span&gt; ((eq &#39;and (car goal-term))
                          `(match-ands &#39;,(replace-anonymous (rest goal-term)) +succeed+ ,facts))
                         ((eq &#39;or (car goal-term))
                          `(match-ors &#39;,(replace-anonymous (rest goal-term)) +succeed+ ,facts))
                         (t
                          `(match-single &#39;,goal-term +succeed+ ,facts))))
   ...&lt;/pre&gt;

&lt;p&gt;we&#39;re setting up some name sanitation for certain words we&#39;d like to use in the definition that should still be usable by the callers of &lt;code&gt;for-all&lt;/code&gt;. Note the use of &lt;code&gt;replace-anonymous&lt;/code&gt;, the definition can be found in Norvig&#39;s prolog implementation. The entirety of that &lt;code&gt;cond&lt;/code&gt; decides which of our matchers we&#39;re going to use to traverse our corpus.&lt;/p&gt;

&lt;pre&gt;            ...
            ,@(&lt;span style=&quot;color: #a020f0;&quot;&gt;unless&lt;/span&gt; apply
              `((,template &#39;,(replace-anonymous (or get goal-term))))))
            ...&lt;/pre&gt;

&lt;p&gt;If we get passed the &lt;code&gt;apply&lt;/code&gt; argument, we&#39;ll be doing something special later. Otherwise, we&#39;ll want to slot our results into the template in &lt;code&gt;gen&lt;/code&gt;, and failing &lt;i&gt;that&lt;/i&gt;, just slot it back into the querying goal form.&lt;/p&gt;

&lt;pre&gt;       ...
       (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for ,res = (funcall ,gen)
          while ,res collect ,(&lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; apply
                                  `(apply (&lt;span style=&quot;color: #a020f0;&quot;&gt;lambda&lt;/span&gt; ,(variables-in apply) ,apply)
                                          (subst-bindings ,res &#39;,(variables-in apply)))
                                  `(subst-bindings ,res ,template))))))&lt;/pre&gt;

&lt;p&gt;And that&#39;s the meat of it. We&#39;re going to be grabbing results out of our generator. As you can see, the special thing we&#39;re doing with the &lt;code&gt;apply&lt;/code&gt; argument is stitching up a function to &lt;code&gt;apply&lt;/code&gt; to a substituted list of our results. If we didn&#39;t get an &lt;code&gt;apply&lt;/code&gt;, we&#39;re just slotting said result back into the &lt;code&gt;template&lt;/code&gt; we defined earlier. I find that seeing some macroexpansions really helps understanding at this stage. So, here are the basics:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Plain single-goal:&lt;/b&gt;&lt;/p&gt;
&lt;pre&gt;CL-USER&amp;gt; (macroexpand &#39;(for-all (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:author&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; my-fact-base))
(&lt;span style=&quot;color: #a020f0;&quot;&gt;LET*&lt;/span&gt; ((#&lt;span style=&quot;color: #483d8b;&quot;&gt;:FACTS1073&lt;/span&gt; MY-FACT-BASE)
       (#&lt;span style=&quot;color: #483d8b;&quot;&gt;:GEN1071&lt;/span&gt;
        (MATCH-SINGLE &#39;(?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:AUTHOR&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) +SUCCEED+ #&lt;span style=&quot;color: #483d8b;&quot;&gt;:FACTS1073&lt;/span&gt;))
       (#&lt;span style=&quot;color: #483d8b;&quot;&gt;:TEMPLATE1070&lt;/span&gt; &#39;(?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:AUTHOR&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;)))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;LOOP&lt;/span&gt; FOR #&lt;span style=&quot;color: #483d8b;&quot;&gt;:RES1072&lt;/span&gt; = (FUNCALL #&lt;span style=&quot;color: #483d8b;&quot;&gt;:GEN1071&lt;/span&gt;)
        WHILE #&lt;span style=&quot;color: #483d8b;&quot;&gt;:RES1072&lt;/span&gt;
        COLLECT (SUBST-BINDINGS #&lt;span style=&quot;color: #483d8b;&quot;&gt;:RES1072&lt;/span&gt; #&lt;span style=&quot;color: #483d8b;&quot;&gt;:TEMPLATE1070&lt;/span&gt;)))
T&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;&lt;code&gt;or&lt;/code&gt;-goals:&lt;/b&gt;&lt;/p&gt;
&lt;pre&gt;CL-USER&amp;gt; (macroexpand &#39;(for-all (or (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:author&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:message&lt;/span&gt; ?message)) &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; my-fact-base))
(&lt;span style=&quot;color: #a020f0;&quot;&gt;LET*&lt;/span&gt; ((#&lt;span style=&quot;color: #483d8b;&quot;&gt;:FACTS1077&lt;/span&gt; MY-FACT-BASE)
       (#&lt;span style=&quot;color: #483d8b;&quot;&gt;:GEN1075&lt;/span&gt;
        (MATCH-ORS &#39;((?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:AUTHOR&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) (?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:MESSAGE&lt;/span&gt; ?MESSAGE))
                   +SUCCEED+ #&lt;span style=&quot;color: #483d8b;&quot;&gt;:FACTS1077&lt;/span&gt;))
       (#&lt;span style=&quot;color: #483d8b;&quot;&gt;:TEMPLATE1074&lt;/span&gt; &#39;(OR (?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:AUTHOR&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) (?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:MESSAGE&lt;/span&gt; ?MESSAGE))))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;LOOP&lt;/span&gt; FOR #&lt;span style=&quot;color: #483d8b;&quot;&gt;:RES1076&lt;/span&gt; = (FUNCALL #&lt;span style=&quot;color: #483d8b;&quot;&gt;:GEN1075&lt;/span&gt;)
        WHILE #&lt;span style=&quot;color: #483d8b;&quot;&gt;:RES1076&lt;/span&gt;
        COLLECT (SUBST-BINDINGS #&lt;span style=&quot;color: #483d8b;&quot;&gt;:RES1076&lt;/span&gt; #&lt;span style=&quot;color: #483d8b;&quot;&gt;:TEMPLATE1074&lt;/span&gt;)))
T&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;&lt;code&gt;and&lt;/code&gt;-goals:&lt;/b&gt;&lt;/p&gt;
&lt;pre&gt;CL-USER&amp;gt; (macroexpand &#39;(for-all (and (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:author&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:message&lt;/span&gt; ?message)) &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; my-fact-base))
(&lt;span style=&quot;color: #a020f0;&quot;&gt;LET*&lt;/span&gt; ((#&lt;span style=&quot;color: #483d8b;&quot;&gt;:FACTS1081&lt;/span&gt; MY-FACT-BASE)
       (#&lt;span style=&quot;color: #483d8b;&quot;&gt;:GEN1079&lt;/span&gt;
        (MATCH-ANDS &#39;((?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:AUTHOR&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) (?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:MESSAGE&lt;/span&gt; ?MESSAGE))
                    +SUCCEED+ #&lt;span style=&quot;color: #483d8b;&quot;&gt;:FACTS1081&lt;/span&gt;))
       (#&lt;span style=&quot;color: #483d8b;&quot;&gt;:TEMPLATE1078&lt;/span&gt;
        &#39;(AND (?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:AUTHOR&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) (?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:MESSAGE&lt;/span&gt; ?MESSAGE))))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;LOOP&lt;/span&gt; FOR #&lt;span style=&quot;color: #483d8b;&quot;&gt;:RES1080&lt;/span&gt; = (FUNCALL #&lt;span style=&quot;color: #483d8b;&quot;&gt;:GEN1079&lt;/span&gt;)
        WHILE #&lt;span style=&quot;color: #483d8b;&quot;&gt;:RES1080&lt;/span&gt;
        COLLECT (SUBST-BINDINGS #&lt;span style=&quot;color: #483d8b;&quot;&gt;:RES1080&lt;/span&gt; #&lt;span style=&quot;color: #483d8b;&quot;&gt;:TEMPLATE1078&lt;/span&gt;)))
T&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;Using the &lt;code&gt;&lt;span style=&quot;color: #483d8b;&quot;&gt;:get&lt;/span&gt;&lt;/code&gt; option&lt;/b&gt;&lt;/p&gt;
&lt;pre&gt;CL-USER&amp;gt; (macroexpand &#39;(for-all (and (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:author&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:message&lt;/span&gt; ?message)) &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; my-fact-base &lt;span style=&quot;color: #483d8b;&quot;&gt;:get&lt;/span&gt; ?message))
(&lt;span style=&quot;color: #a020f0;&quot;&gt;LET*&lt;/span&gt; ((#&lt;span style=&quot;color: #483d8b;&quot;&gt;:FACTS1085&lt;/span&gt; MY-FACT-BASE)
       (#&lt;span style=&quot;color: #483d8b;&quot;&gt;:GEN1083&lt;/span&gt;
        (MATCH-ANDS &#39;((?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:AUTHOR&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) (?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:MESSAGE&lt;/span&gt; ?MESSAGE))
                    +SUCCEED+ #&lt;span style=&quot;color: #483d8b;&quot;&gt;:FACTS1085&lt;/span&gt;))
       (#&lt;span style=&quot;color: #483d8b;&quot;&gt;:TEMPLATE1082&lt;/span&gt; &#39;?MESSAGE))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;LOOP&lt;/span&gt; FOR #&lt;span style=&quot;color: #483d8b;&quot;&gt;:RES1084&lt;/span&gt; = (FUNCALL #&lt;span style=&quot;color: #483d8b;&quot;&gt;:GEN1083&lt;/span&gt;)
        WHILE #&lt;span style=&quot;color: #483d8b;&quot;&gt;:RES1084&lt;/span&gt;
        COLLECT (SUBST-BINDINGS #&lt;span style=&quot;color: #483d8b;&quot;&gt;:RES1084&lt;/span&gt; #&lt;span style=&quot;color: #483d8b;&quot;&gt;:TEMPLATE1082&lt;/span&gt;)))
T&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;Using the &lt;code&gt;&lt;span style=&quot;color: #483d8b;&quot;&gt;:apply&lt;/span&gt;&lt;/code&gt; option&lt;/b&gt;&lt;/p&gt;
&lt;pre&gt;CL-USER&amp;gt; (macroexpand &#39;(for-all (and (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:author&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) (?id &lt;span style=&quot;color: #483d8b;&quot;&gt;:message&lt;/span&gt; ?message)) &lt;span style=&quot;color: #483d8b;&quot;&gt;:in&lt;/span&gt; my-fact-base &lt;span style=&quot;color: #483d8b;&quot;&gt;:apply&lt;/span&gt; (format t &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;~s~%   -Inaimathi&quot;&lt;/span&gt; ?message)))
(&lt;span style=&quot;color: #a020f0;&quot;&gt;LET*&lt;/span&gt; ((#&lt;span style=&quot;color: #483d8b;&quot;&gt;:FACTS1089&lt;/span&gt; MY-FACT-BASE)
       (#&lt;span style=&quot;color: #483d8b;&quot;&gt;:GEN1087&lt;/span&gt;
        (MATCH-ANDS &#39;((?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:AUTHOR&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi&quot;&lt;/span&gt;) (?ID &lt;span style=&quot;color: #483d8b;&quot;&gt;:MESSAGE&lt;/span&gt; ?MESSAGE))
                    +SUCCEED+ #&lt;span style=&quot;color: #483d8b;&quot;&gt;:FACTS1089&lt;/span&gt;)))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;LOOP&lt;/span&gt; FOR #&lt;span style=&quot;color: #483d8b;&quot;&gt;:RES1088&lt;/span&gt; = (FUNCALL #&lt;span style=&quot;color: #483d8b;&quot;&gt;:GEN1087&lt;/span&gt;)
        WHILE #&lt;span style=&quot;color: #483d8b;&quot;&gt;:RES1088&lt;/span&gt;
        COLLECT (APPLY
                 (&lt;span style=&quot;color: #a020f0;&quot;&gt;LAMBDA&lt;/span&gt; (?MESSAGE) (FORMAT T &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;~s~%   -Inaimathi&quot;&lt;/span&gt; ?MESSAGE))
                 (SUBST-BINDINGS #&lt;span style=&quot;color: #483d8b;&quot;&gt;:RES1088&lt;/span&gt; &#39;(?MESSAGE)))))
T
CL-USER&amp;gt; &lt;/pre&gt;

&lt;p&gt;And that&#39;s that. Granted, the &lt;i&gt;implementation&lt;/i&gt; is a bit more complicated than just writing manual loops, but I&#39;m convinced there are a couple wins here. Firstly, the invocation is simpler, which means that the above definitions will eventually &quot;pay for themselves&quot; in terms of complexity. Secondly, it seems like I could fairly easily mod this into &lt;a href=&quot;http://common-lisp.net/project/parenscript/&quot;&gt;&lt;code&gt;parenscript&lt;/code&gt;&lt;/a&gt;-friendly forms, which means this&#39;ll save me from having to convert fact-bases to object lists on the client side. But that&#39;s something I&#39;ll tell you about next time.&lt;/p&gt;

&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Thu-Apr-10-000043EDT-2014&quot; name=&quot;foot-Thu-Apr-10-000043EDT-2014&quot;&gt;[back]&lt;/a&gt; - Almost always using the question-mark-prefix notation for logic variables for some reason. I&#39;m not sure what the approach gains or loses you yet. I guess in the case of miniKanren, it gains you the ability to unify on vectors since there&#39;s no ambiguity, and it might make it easier to read the resulting programs, but I&#39;m not banking on that.&lt;/p&gt;

&lt;p&gt;2 - &lt;a href=&quot;#note-Thu-Apr-10-000046EDT-2014&quot; name=&quot;foot-Thu-Apr-10-000046EDT-2014&quot;&gt;[back]&lt;/a&gt; - Though do go over Norvig&#39;s version to see a dissection of the common bugs.&lt;/p&gt;

&lt;p&gt;3 - &lt;a href=&quot;#note-Thu-Apr-10-000130EDT-2014&quot; name=&quot;foot-Thu-Apr-10-000130EDT-2014&quot;&gt;[back]&lt;/a&gt; - And remember, &lt;code&gt;backtrack!&lt;/code&gt; itself fails if it runs out of search space.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/5956460889232131318/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2014/04/querying-fact-bases.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/5956460889232131318'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/5956460889232131318'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2014/04/querying-fact-bases.html' title='Querying Fact Bases'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjudHBfk1d39sTYBEz_B4DqC25w4otrmuX3Duo2G0u2b6U7k361XUWcqT4mIJ1EQ93Q6QaQnrKwlMUzU2pNfWSxZIo0Hkjq6mFMxzzTK2-8EgsfXfrp53eJa4wZ4qSY1Dm335z4vcTXR525/s72-c/trek-dreadlocks-resettable-combination-cable-lock.jpg" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-6659168099552750211</id><published>2014-04-05T15:04:00.002-07:00</published><updated>2014-04-20T06:53:08.237-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Common Lisp"/><title type='text'>Buildapp Minutia</title><content type='html'>&lt;p&gt;Before I get to telling you &lt;a href=&quot;https://github.com/Inaimathi/cl-notebook#cl-notebook&quot;&gt;what I&#39;ve been up to lately&lt;/a&gt;, let me share some insight into what it takes to build Lisp executables on Windows and Linux. This is something I had to do recently at work. I wouldn&#39;t normally bother, but we still have Windows dev boxes, and it seemed like an interesting enough exercise. In no particular order, here are things you need to think about when you&#39;re putting things together with &lt;a href=&quot;http://www.xach.com/lisp/buildapp/&quot;&gt;&lt;code&gt;buildapp&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Be careful with your storage folders&lt;/h3&gt;

&lt;p&gt;My usual tactic for this sort of thing is to store static files and stored files in the project directory. It&#39;s easy to do because I just get to use relative paths everywhere, and it works well enough if your distribution plan is basically &lt;code&gt;git clone https://github.com/you/whatever.git&lt;/code&gt;. The only downside is that you have to run the program in the context of its project directory, or have random &lt;code&gt;static&lt;/code&gt; folders pop up in random places.&lt;/p&gt;

&lt;p&gt;For people who don&#39;t just randomly write Lisp code for fun, this isn&#39;t exactly acceptable. To do proper binary deployment for a more general audience, you need to make sure that there&#39;s a single consistent place for your program to store stuff. And if you want to be cross-platform about it, you can&#39;t just do &lt;code&gt;(defvar *storage* &quot;~/project-name/&quot;)&lt;/code&gt; and call it a day. Fortunately, &lt;a href=&quot;http://www.lispworks.com/documentation/HyperSpec/Body/f_user_h.htm#user-homedir-pathname&quot;&gt;&lt;code&gt;user-homedir-pathname&lt;/code&gt;&lt;/a&gt; is a thing, so what I ended up doing is setting my storage directory to &lt;code&gt;(merge-pathnames &quot;.project-name/&quot; (user-homedir-pathname))&lt;/code&gt;. However, it wasn&#39;t quite that simple.&lt;/p&gt;

&lt;p&gt;My &lt;i&gt;other&lt;/i&gt; usual tactic is to just put such config variable declarations in the appropriate &lt;code&gt;package.lisp&lt;/code&gt; file, and leave it at that. Unfortunately, when I tried that with &lt;code&gt;buildapp&lt;/code&gt;, the first teammate who tried it responded with&lt;/p&gt;

&lt;blockquote&gt;Why is this complaining that &quot;C:\Users\Inaimathi\2dmacs\&quot; doesn&#39;t exist?&lt;/blockquote&gt;

&lt;p&gt;The problem is that &lt;code&gt;buildapp&lt;/code&gt; takes your image and binary and ships it, including anything you did at compile or config time. What I really wanted was for my binary to check &lt;i&gt;at runtime&lt;/i&gt; what the users&#39; home directory is and use that as the starting point for its own storage directory. The way I ended up doing that, though I&#39;m sure others are possible, was to define the appropriate variables where I&#39;d usually put them, then set them again in the entry-point function. Mine happened to be called &lt;code&gt;main&lt;/code&gt;, because why not, so what you&#39;d see if you looked into the appropriate files is&lt;a href=&quot;#foot-Sat-Apr-05-175204EDT-2014&quot; name=&quot;note-Sat-Apr-05-175204EDT-2014&quot;&gt;[1]&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;package.lisp
&lt;/span&gt;
...

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defparameter&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;*storage*&lt;/span&gt; nil)

...&lt;/pre&gt;

&lt;pre&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;start.lisp
&lt;/span&gt;
...

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;main&lt;/span&gt; (&lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;optional&lt;/span&gt; argv)
  ...
  (setf *storage* (merge-pathnames &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;.2dmacs/&quot;&lt;/span&gt; (user-homedir-pathname)))
  ...
  )&lt;/pre&gt;

&lt;p&gt;That lets the appropriate functions access storage files, but makes sure that &lt;code&gt;*storage*&lt;/code&gt; will ultimately be set to the appropriate directory on the users&#39; machine rather than yours.&lt;/p&gt;

&lt;h3&gt;Native SBCL shell sucks balls under Windows&lt;/h3&gt;

&lt;p&gt;We had a couple problems deploying a specific part of the system that dealt with running external programs. And like the title says, that was balls on Windows. Not that I expected it to run perfectly across operating systems, but it turned out to be particularly thorny. First off, &lt;code&gt;external-program&lt;/code&gt; doesn&#39;t do what we wanted. It kinda does, but doesn&#39;t seem to let you have a hook in to search the users&#39; environment variables for program locations. Luckily, we&#39;re using SBCL, and its native &lt;code&gt;sb-ext:run-program&lt;/code&gt; &lt;i&gt;does&lt;/i&gt; give you this facility in the form of the &lt;code&gt;search&lt;/code&gt; keyword argument. Also, for some reason SBCL handles streams really oddly in Windows? Not sure why, but the end result was that I couldn&#39;t capture &lt;code&gt;*standard-output*&lt;/code&gt; in the way I wanted to in one part of the code. We ended up dealing with that by calling &lt;code&gt;sb-ext:run-program&lt;/code&gt; with &lt;code&gt;:output :stream&lt;/code&gt;, then collecting the result through &lt;code&gt;sb-ext:process-output&lt;/code&gt; instead of direct stream capture. Cool, I guess. It &lt;i&gt;seemed&lt;/i&gt; to work in testing. But the particular shell command we were using started seizing up once we hit a particular corpus size&lt;a href=&quot;#foot-Sat-Apr-05-175223EDT-2014&quot; name=&quot;note-Sat-Apr-05-175223EDT-2014&quot;&gt;[2]&lt;/a&gt;. The solution we ended up taking was using &lt;code&gt;uiop:run-program&lt;/code&gt; instead. It deals with streams the way I was expecting &lt;i&gt;and&lt;/i&gt; handles all shell commands we&#39;ve thrown at it so far very snappily.&lt;/p&gt;
 
&lt;h3&gt;Finding dependencies is ... non-trivial&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;buildapp&lt;/code&gt; doesn&#39;t load dependencies automatically. It expects you to pass it a bunch of &lt;code&gt;--load-system&lt;/code&gt; command line arguments for things you want included in the final binary. The first thing I did was check the docs. There didn&#39;t seem to be a &lt;code&gt;dependency-tree&lt;/code&gt; call anywhere, so I wrote &lt;a href=&quot;http://stackoverflow.com/a/22732580/190887&quot;&gt;this one&lt;/a&gt;. On a whim though, I dropped by &lt;code&gt;#lisp&lt;/code&gt;, where I got the opportunity to ask &lt;a href=&quot;http://xach.com/&quot;&gt;Zach&lt;/a&gt; about it&lt;a href=&quot;#foot-Sat-Apr-05-175227EDT-2014&quot; name=&quot;note-Sat-Apr-05-175227EDT-2014&quot;&gt;[3]&lt;/a&gt;. It turns out that what I wrote is really only going to get you the dependencies declared in &lt;code&gt;asdf&lt;/code&gt; files, and there are apparently enough people out there who hook manual &lt;code&gt;load&lt;/code&gt; or &lt;code&gt;ql:quickload&lt;/code&gt; statements in through odd, ad-hoc ways that he doesn&#39;t go that route. Turns out that what he does is &lt;code&gt;asdf:load-system&lt;/code&gt;/&lt;code&gt;ql:quickload&lt;/code&gt; the thing he wants to build, then runs &lt;code&gt;ql:write-asdf-manifest-file&lt;/code&gt; to find the list of all systems included in the image after everything relevant has been loaded. The &lt;code&gt;buildapp&lt;/code&gt; call you make after that needs to look something like &lt;code&gt;buildapp --manifest-file wherever/you/had/ql:write-manifest-file/output.txt --load-system foo --load-system bar ... --entry your-entry-fn --output your-program-name&lt;/code&gt;. Mildly annoying, but at least it&#39;ll get you what you need.&lt;/p&gt;

&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Sat-Apr-05-175204EDT-2014&quot; name=&quot;foot-Sat-Apr-05-175204EDT-2014&quot;&gt;[back]&lt;/a&gt; - Ok, it&#39;s mildly more complicated than this too, because I wanted to deal with some command line arguments, and I wanted some static files to be &lt;i&gt;optionally&lt;/i&gt; re-generated at each program load. You can still see the basic principle.&lt;/p&gt;

&lt;p&gt;2 - &lt;a href=&quot;#note-Sat-Apr-05-175223EDT-2014&quot; name=&quot;foot-Sat-Apr-05-175223EDT-2014&quot;&gt;[back]&lt;/a&gt; - If you must know, it was &lt;code&gt;git ls-tree&lt;/code&gt;, and the call started hanging around the time that we committed the ~third file into the target repository.&lt;/p&gt;

&lt;p&gt;3 - &lt;a href=&quot;#note-Sat-Apr-05-175227EDT-2014&quot; name=&quot;foot-Sat-Apr-05-175227EDT-2014&quot;&gt;[back]&lt;/a&gt; - Here&#39;s the transcript, for those of you who want the details:&lt;/p&gt;

&lt;pre&gt;13:58 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;inaimathi&lt;/span&gt;&amp;gt; Anyone here who knows things about asdf
                  dependencies, and is willing to answer
                  questions/lend an eye?
13:58 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;Xach&lt;/span&gt;&amp;gt; inaimathi: I know a bit. What&#39;s up?
13:59 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;inaimathi&lt;/span&gt;&amp;gt; I&#39;m trying to find the dependency tree
                  (preferably ordered) of a given asdf system.
13:59 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;inaimathi&lt;/span&gt;&amp;gt; Is there a build-in way of doing that?
13:59 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;inaimathi&lt;/span&gt;&amp;gt; *built
13:59 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;inaimathi&lt;/span&gt;&amp;gt; Hm
14:00 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;inaimathi&lt;/span&gt;&amp;gt; Actually, you might be able to help with the
                  larger problem too. The real problem is that I&#39;m
                  trying to run buildapp for a project, and I want
                  to know what systems I need to load as part of
                  the shell command.
14:00 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;Xach&lt;/span&gt;&amp;gt; oh. the way i do that is to load the project once with
             dependencies downloaded automatically and then note
             what was loaded.
14:00 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;Xach&lt;/span&gt;&amp;gt; then i load it again with just those things.
14:01 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;Xach&lt;/span&gt;&amp;gt; it is not great but arbitrary things load during
             find-system time so i&#39;m not sure if there&#39;s a nice way
             around it.
14:01 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;inaimathi&lt;/span&gt;&amp;gt; How do I go about doing that?
14:02 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;inaimathi&lt;/span&gt;&amp;gt; That is, loading a project while getting output
                  of what&#39;s being loaded. Is there a ql flag or
                  something?
14:03 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;Xach&lt;/span&gt;&amp;gt; inaimathi: i don&#39;t actually note the specifics. i just
             load it, and then have quicklisp dump out an index to
             the currently installed libraries via
             (ql:write-asdf-manifest-file
             &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;/path/to/my/project/system-index.txt&quot;&lt;/span&gt;)
14:03 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;inaimathi&lt;/span&gt;&amp;gt; Ah
14:03 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;Xach&lt;/span&gt;&amp;gt; then i use buildapp --asdf-manifest system-index.txt
             --&amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;the&lt;/span&gt; rest of the stuff&amp;gt;
14:04 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;Xach&lt;/span&gt;&amp;gt; Each time I make a new project I refine the makefile
             technique a little more
14:05 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;inaimathi&lt;/span&gt;&amp;gt; Ok then. Do you think something like
                  http://stackoverflow.com/a/22732580/190887 could
                  be a valid approach, or is that going to miss
                  things?
14:07 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;Xach&lt;/span&gt;&amp;gt; inaimathi: One difficulty arises from .asd files with
             things like (eval-when ... (asdf:load-system
             &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;some-prerequisite&quot;&lt;/span&gt;))
14:07 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;inaimathi&lt;/span&gt;&amp;gt; Right; those wouldn&#39;t be noted by the asdf system
                  itself.
14:07 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;inaimathi&lt;/span&gt;&amp;gt; Dammit.
14:08 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;Xach&lt;/span&gt;&amp;gt; I also don&#39;t know if the slot you&#39;re looking at
             includes :defsystem-depends-on dependencies.
14:08 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;Xach&lt;/span&gt;&amp;gt; inaimathi: I once asked about how to do this on
             asdf-devel and I got an answer I didn&#39;t really
             understand (it was complicated) and I haven&#39;t
             revisited it. And I&#39;m not sure there&#39;s an archive you
             can search for it.
14:09 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;rtoym&lt;/span&gt;&amp;gt; asdf-devel is on gmane.org
14:10 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;inaimathi&lt;/span&gt;&amp;gt; Hm. I&#39;ll take the asdf-manifest-file approach for
                  the moment, and probably ask around on asdf-devel
                  later.
14:10 &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;inaimathi&lt;/span&gt;&amp;gt; Thanks!
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/6659168099552750211/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2014/04/buildapp-minutia.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/6659168099552750211'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/6659168099552750211'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2014/04/buildapp-minutia.html' title='Buildapp Minutia'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-6470595176360528471</id><published>2014-03-25T12:04:00.001-07:00</published><updated>2014-03-29T08:17:22.315-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Almost Literate Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="Common Lisp"/><category scheme="http://www.blogger.com/atom/ns#" term="Databases"/><title type='text'>Fact Base Indices</title><content type='html'>&lt;p&gt;Got through a late-night programming binge, followed by more of the same on my lunch break, followed by a couple more days of thought and work during downtime. It&#39;s up at my &lt;a href=&quot;https://github.com/Inaimathi/fact-base&quot;&gt;fact-base implementation&lt;/a&gt;. Basically, we have indices now. Fairly naive, simple indices, but they should suffice for what I&#39;m up to&lt;a href=&quot;#foot-Tue-Mar-25-150513EDT-2014&quot; name=&quot;note-Tue-Mar-25-150513EDT-2014&quot;&gt;[1]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Before we get to discussing any code, lets back up and discuss the idea of an &lt;code&gt;index&lt;/code&gt; for a moment.&lt;/p&gt;

&lt;h3&gt;The Idea of an &lt;code&gt;index&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;An &lt;code&gt;index&lt;/code&gt; in this context is an extra layer on top of our fact storage engine that keeps track of what we&#39;ve put in/taken out in a way that makes certain things easier to look up. It&#39;s easier for fact-bases than it is for relational databases. Since every fact is made up of three components&lt;a href=&quot;#foot-Tue-Mar-25-150529EDT-2014&quot; name=&quot;note-Tue-Mar-25-150529EDT-2014&quot;&gt;[3]&lt;/a&gt;, all we have to do is keep an index by one or two slots. What we&#39;re basically looking to do is a really fast lookup of some subset of all facts in a base based on one or two of those keys&lt;a href=&quot;#foot-Tue-Mar-25-150535EDT-2014&quot; name=&quot;note-Tue-Mar-25-150535EDT-2014&quot;&gt;[4]&lt;/a&gt;. The way I&#39;ve chosen to do it, after some advice from friends who&#39;ve used systems something like this, is by maintaining hash tables&lt;a href=&quot;#foot-Tue-Mar-25-150538EDT-2014&quot; name=&quot;note-Tue-Mar-25-150538EDT-2014&quot;&gt;[5]&lt;/a&gt; in memory that give you shortcuts to some specified indices. We&#39;re trading space&lt;a href=&quot;#foot-Tue-Mar-25-150541EDT-2014&quot; name=&quot;note-Tue-Mar-25-150541EDT-2014&quot;&gt;[6]&lt;/a&gt; for time&lt;a href=&quot;#foot-Tue-Mar-25-150544EDT-2014&quot; name=&quot;note-Tue-Mar-25-150544EDT-2014&quot;&gt;[7]&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;The Post-Explanation Version&lt;/h3&gt;

&lt;p&gt;This was a much different article initially; I was going to discuss some bone-headed intermediate states for this code before getting to the &quot;final&quot;&lt;a href=&quot;#foot-Tue-Mar-25-150547EDT-2014&quot; name=&quot;note-Tue-Mar-25-150547EDT-2014&quot;&gt;[8]&lt;/a&gt;. It ended up looking like a stupid idea in this particular instance because the previous versions weren&#39;t things I&#39;d consider running after having thought through it a bit more. &lt;/p&gt;

&lt;p&gt;I try to do that a fair amount these days.&lt;/p&gt; 

&lt;p&gt;Not the stupid implementations thing, though that&#39;s also true. I mean sit down with another actual human being and talk them through the code I just wrote. It&#39;s not &lt;i&gt;quite&lt;/i&gt; as good as blogging about it, but it&#39;s faster and turns up almost as many issues. It also has an added benefit that blogging doesn&#39;t seem to give me, which is showing me when I&#39;m completely off my nut. Anyhow, here&#39;s what I had after I explained the thing to someone, poured some shower time into thinking about it, and drafting the first version of this post:&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;in-package&lt;/span&gt; #&lt;span style=&quot;color: #483d8b;&quot;&gt;:fact-base&lt;/span&gt;)

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defclass&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;index&lt;/span&gt; ()
  ((table &lt;span style=&quot;color: #483d8b;&quot;&gt;:reader&lt;/span&gt; table &lt;span style=&quot;color: #483d8b;&quot;&gt;:initform&lt;/span&gt; (make-hash-table &lt;span style=&quot;color: #483d8b;&quot;&gt;:test&lt;/span&gt; &#39;equal))))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;make-index&lt;/span&gt; (indices)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((index (make-instance &#39;index)))
    (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for ix in indices
       do (setf (gethash ix (table index))
                (make-hash-table &lt;span style=&quot;color: #483d8b;&quot;&gt;:test&lt;/span&gt; &#39;equal)))
    index))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;indexed?&lt;/span&gt; ((state index) (ix-type symbol))
  (gethash ix-type (table state)))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;decide-index&lt;/span&gt; (&lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;optional&lt;/span&gt; a b c)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;cond&lt;/span&gt; ((and a b c) (list &lt;span style=&quot;color: #483d8b;&quot;&gt;:abc&lt;/span&gt; a b c))
        ((and a b) (list &lt;span style=&quot;color: #483d8b;&quot;&gt;:ab&lt;/span&gt; a b))
        ((and a c) (list &lt;span style=&quot;color: #483d8b;&quot;&gt;:ac&lt;/span&gt; a c))
        ((and b c) (list &lt;span style=&quot;color: #483d8b;&quot;&gt;:bc&lt;/span&gt; b c))
        ((and a) (list &lt;span style=&quot;color: #483d8b;&quot;&gt;:a&lt;/span&gt; a))
        ((and b) (list &lt;span style=&quot;color: #483d8b;&quot;&gt;:b&lt;/span&gt; b))
        ((and c) (list &lt;span style=&quot;color: #483d8b;&quot;&gt;:c&lt;/span&gt; c))))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;format-index&lt;/span&gt; ((ix-type symbol) (fact list))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;destructuring-bind&lt;/span&gt; (a b c) fact
    (&lt;span style=&quot;color: #a020f0;&quot;&gt;case&lt;/span&gt; ix-type
      (&lt;span style=&quot;color: #483d8b;&quot;&gt;:abc&lt;/span&gt; (list a b c))
      (&lt;span style=&quot;color: #483d8b;&quot;&gt;:ab&lt;/span&gt; (list a b))
      (&lt;span style=&quot;color: #483d8b;&quot;&gt;:ac&lt;/span&gt; (list a c))
      (&lt;span style=&quot;color: #483d8b;&quot;&gt;:bc&lt;/span&gt; (list b c))
      (&lt;span style=&quot;color: #483d8b;&quot;&gt;:a&lt;/span&gt; (list a))
      (&lt;span style=&quot;color: #483d8b;&quot;&gt;:b&lt;/span&gt; (list b))
      (&lt;span style=&quot;color: #483d8b;&quot;&gt;:c&lt;/span&gt; (list c)))))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;map-insert!&lt;/span&gt; ((facts list) (state index))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;dolist&lt;/span&gt; (f facts) (insert! f state)))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;insert!&lt;/span&gt; ((fact list) (state index))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for ix being the hash-keys of (table state)
     for ix-table being the hash-values of (table state)
     do (push fact (gethash (format-index ix fact) ix-table))))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;delete!&lt;/span&gt; ((fact list) (state index))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for ix being the hash-keys of (table state)
     for ix-table being the hash-values of (table state)
     for formatted = (format-index ix fact)
     do (setf (gethash formatted ix-table) 
              (remove fact (gethash formatted ix-table) &lt;span style=&quot;color: #483d8b;&quot;&gt;:test&lt;/span&gt; #&#39;equal &lt;span style=&quot;color: #483d8b;&quot;&gt;:count&lt;/span&gt; 1))
     unless (gethash formatted ix-table) do (remhash formatted ix-table)))

&lt;span style=&quot;color: #b22222;&quot;&gt;;;;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;Show methods
&lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;Entirely for debugging purposes. 
&lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;Do not use in production. 
&lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;Seriously.
&lt;/span&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;show&lt;/span&gt; (thing &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;optional&lt;/span&gt; (depth 0))
  (format t &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;~a~a&quot;&lt;/span&gt; (make-string depth &lt;span style=&quot;color: #483d8b;&quot;&gt;:initial-element&lt;/span&gt; #\space) thing))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;show&lt;/span&gt; ((tbl hash-table) &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;optional&lt;/span&gt; (depth 0))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for k being the hash-keys of tbl
     for v being the hash-values of tbl
     do (format t &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;~a~5@a -&amp;gt;~%&quot;&lt;/span&gt; 
                (make-string depth &lt;span style=&quot;color: #483d8b;&quot;&gt;:initial-element&lt;/span&gt; #\space) k)
     do (show v (+ depth 8))
     do (format t &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;~%&quot;&lt;/span&gt;)))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;show&lt;/span&gt; ((ix index) &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;optional&lt;/span&gt; (depth 0))
  (show (table ix) depth))&lt;/pre&gt;

&lt;p&gt;There, that&#39;s not so intimidating, is it? The actual interface to these indices is in &lt;a href=&quot;https://github.com/Inaimathi/fact-base/blob/master/fact-base.lisp#L45-L58&quot;&gt;&lt;code&gt;fact-base.lisp&lt;/code&gt;&lt;/a&gt;, but the above contains most of the functionality. First, ignore the &lt;code&gt;show&lt;/code&gt; methods at the bottom there. That was just a piece of hackery to give me a usable visual representation of an index while I was debugging this beast. Lets start at the top.&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defclass&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;index&lt;/span&gt; ()
  ((table &lt;span style=&quot;color: #483d8b;&quot;&gt;:reader&lt;/span&gt; table &lt;span style=&quot;color: #483d8b;&quot;&gt;:initform&lt;/span&gt; (make-hash-table &lt;span style=&quot;color: #483d8b;&quot;&gt;:test&lt;/span&gt; &#39;equal))))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;make-index&lt;/span&gt; (indices)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((index (make-instance &#39;index)))
    (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for ix in indices
       do (setf (gethash ix (table index))
                (make-hash-table &lt;span style=&quot;color: #483d8b;&quot;&gt;:test&lt;/span&gt; &#39;equal)))
    index))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;indexed?&lt;/span&gt; ((state index) (ix-type symbol))
  (gethash ix-type (table state)))&lt;/pre&gt;

&lt;p&gt;An &lt;code&gt;index&lt;/code&gt; has a table of bindings. You&#39;d call &lt;code&gt;make-index&lt;/code&gt; in a way resembling &lt;code&gt;(make-index &#39;(:a :b :bc :ac))&lt;/code&gt;, which would give you back an &lt;code&gt;index&lt;/code&gt; with room to dissect a fact base into chunklets keyed off of&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;the first element&lt;/li&gt;
  &lt;li&gt;the second element&lt;/li&gt;
  &lt;li&gt;the second then the third element&lt;/li&gt;
  &lt;li&gt;the first then the third element&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No, I have no idea if I&#39;ll ever actually need a setup like this. The &lt;code&gt;indexed?&lt;/code&gt; method takes an &lt;code&gt;index&lt;/code&gt; and an &lt;code&gt;ix-type&lt;/code&gt; symbol and tells you whether the given &lt;code&gt;index&lt;/code&gt; is tracking that particular type of lookup.&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;decide-index&lt;/span&gt; (&lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;optional&lt;/span&gt; a b c)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;cond&lt;/span&gt; ((and a b c) (list &lt;span style=&quot;color: #483d8b;&quot;&gt;:abc&lt;/span&gt; a b c))
        ((and a b) (list &lt;span style=&quot;color: #483d8b;&quot;&gt;:ab&lt;/span&gt; a b))
        ((and a c) (list &lt;span style=&quot;color: #483d8b;&quot;&gt;:ac&lt;/span&gt; a c))
        ((and b c) (list &lt;span style=&quot;color: #483d8b;&quot;&gt;:bc&lt;/span&gt; b c))
        ((and a) (list &lt;span style=&quot;color: #483d8b;&quot;&gt;:a&lt;/span&gt; a))
        ((and b) (list &lt;span style=&quot;color: #483d8b;&quot;&gt;:b&lt;/span&gt; b))
        ((and c) (list &lt;span style=&quot;color: #483d8b;&quot;&gt;:c&lt;/span&gt; c))))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;format-index&lt;/span&gt; ((ix-type symbol) (fact list))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;destructuring-bind&lt;/span&gt; (a b c) fact
    `(,ix-type
      ,@ (&lt;span style=&quot;color: #a020f0;&quot;&gt;case&lt;/span&gt; ix-type
           (&lt;span style=&quot;color: #483d8b;&quot;&gt;:abc&lt;/span&gt; (list a b c))
           (&lt;span style=&quot;color: #483d8b;&quot;&gt;:ab&lt;/span&gt; (list a b))
           (&lt;span style=&quot;color: #483d8b;&quot;&gt;:ac&lt;/span&gt; (list a c))
           (&lt;span style=&quot;color: #483d8b;&quot;&gt;:bc&lt;/span&gt; (list b c))
           (&lt;span style=&quot;color: #483d8b;&quot;&gt;:a&lt;/span&gt; (list a))
           (&lt;span style=&quot;color: #483d8b;&quot;&gt;:b&lt;/span&gt; (list b))
           (&lt;span style=&quot;color: #483d8b;&quot;&gt;:c&lt;/span&gt; (list c))))))&lt;/pre&gt;

&lt;p&gt;Those both map an index type to the components they&#39;ll need for insertion/lookup. I&#39;ve thought about factoring out the obvious pattern, and even wrote some prototype code to do it, but it turns out that for 6 indices, the macrology involved is more complicated than the trivial lookup-table thing. If &lt;code&gt;fact-base&lt;/code&gt; were an arbitrary storage system, this would probably be complicated enough to &lt;code&gt;macro&lt;/code&gt; away, but the whole point is that I&#39;m only ever storing triples. Which means I&#39;m never going to need more &lt;code&gt;index&lt;/code&gt; types than this, and usually much less.&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;map-insert!&lt;/span&gt; ((facts list) (state index))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;dolist&lt;/span&gt; (f facts) (insert! f state)))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;insert!&lt;/span&gt; ((fact list) (state index))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for ix being the hash-keys of (table state)
     for ix-table being the hash-values of (table state)
     do (push fact (gethash (format-index ix fact) ix-table))))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;delete!&lt;/span&gt; ((fact list) (state index))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for ix being the hash-keys of (table state)
     for ix-table being the hash-values of (table state)
     for formatted = (format-index ix fact)
     do (setf (gethash formatted ix-table) 
              (remove fact (gethash formatted ix-table) &lt;span style=&quot;color: #483d8b;&quot;&gt;:test&lt;/span&gt; #&#39;equal &lt;span style=&quot;color: #483d8b;&quot;&gt;:count&lt;/span&gt; 1))
     unless (gethash formatted ix-table) do (remhash formatted ix-table)))&lt;/pre&gt;

&lt;p&gt;These three utility methods at the end are exactly what you&#39;d expect. &lt;code&gt;insert!&lt;/code&gt; takes a fact and an &lt;code&gt;index&lt;/code&gt; and inserts one into the other, into how-many-ever particular lookups that &lt;code&gt;index&lt;/code&gt; is tracking. &lt;code&gt;map-insert!&lt;/code&gt; is a shorthand for inserting a bunch of facts at once into the same &lt;code&gt;index&lt;/code&gt;. And finally, &lt;code&gt;delete!&lt;/code&gt; takes a fact and removes it from all &lt;code&gt;index&lt;/code&gt; lookups, then cleans up empty lookup lists.&lt;/p&gt;

&lt;p&gt;And that&#39;s that. You&#39;ve got a quick run-through of how this works out in practice &lt;a href=&quot;https://github.com/Inaimathi/fact-base#example-usage&quot;&gt;here&lt;/a&gt;. I get the feeling I&#39;ll be talking about deltas, forking and the applications of fact bases before long, but we shall see.&lt;/p&gt;


&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Tue-Mar-25-150513EDT-2014&quot; name=&quot;foot-Tue-Mar-25-150513EDT-2014&quot;&gt;[back]&lt;/a&gt; - Granted, because &quot;what I&#39;m up to&quot; at this point &quot;an almost trivial semi-anonymous forum for a local meetup group&quot;, and &quot;an almost trivial notebook-style REPL for common lisp&quot;, that&#39;s true of almost any data storage technique ever, but still. The naive, index-less storage was giving &lt;a href=&quot;https://github.com/Inaimathi/cl-kanren-trs&quot;&gt;cl-kanren&lt;/a&gt;&lt;a href=&quot;#foot-Tue-Mar-25-150519EDT-2014&quot; name=&quot;note-Tue-Mar-25-150519EDT-2014&quot;&gt;[2]&lt;/a&gt; a bit more trouble than I wanted it to when I pushed the stored entry count past 10000 or so. Which is not satisfactory. So yeah, this index is basically a search-space optimization for my database traversals. I&#39;ll let you know how it goes.&lt;/p&gt;

&lt;p&gt;2 - &lt;a href=&quot;#note-Tue-Mar-25-150519EDT-2014&quot; name=&quot;foot-Tue-Mar-25-150519EDT-2014&quot;&gt;[back]&lt;/a&gt; - Which I&#39;ll also have to talk about before long, if for no reason other than to get some ideas out of my head temporarily.&lt;/p&gt;

&lt;p&gt;3 - &lt;a href=&quot;#note-Tue-Mar-25-150529EDT-2014&quot; name=&quot;foot-Tue-Mar-25-150529EDT-2014&quot;&gt;[back]&lt;/a&gt; - The second two might be compound structures, but it&#39;s still only three top-level elements.&lt;/p&gt;

&lt;p&gt;4 - &lt;a href=&quot;#note-Tue-Mar-25-150535EDT-2014&quot; name=&quot;foot-Tue-Mar-25-150535EDT-2014&quot;&gt;[back]&lt;/a&gt; - If you have none of the three components of the fact you&#39;re looking for, you can&#39;t do better than &quot;all facts&quot;; if you have all of them, you already have the fact you&#39;re looking for. So we&#39;re only interested in the other two cases.&lt;/p&gt;

&lt;p&gt;5 - &lt;a href=&quot;#note-Tue-Mar-25-150538EDT-2014&quot; name=&quot;foot-Tue-Mar-25-150538EDT-2014&quot;&gt;[back]&lt;/a&gt; - There&#39;s no particular reason you couldn&#39;t use some tree structure if you like, but hashes are easy, and they come with Common lisp, so...&lt;/p&gt;

&lt;p&gt;6 - &lt;a href=&quot;#note-Tue-Mar-25-150541EDT-2014&quot; name=&quot;foot-Tue-Mar-25-150541EDT-2014&quot;&gt;[back]&lt;/a&gt; - Which is in ample supply these days.&lt;/p&gt;

&lt;p&gt;7 - &lt;a href=&quot;#note-Tue-Mar-25-150544EDT-2014&quot; name=&quot;foot-Tue-Mar-25-150544EDT-2014&quot;&gt;[back]&lt;/a&gt; - Which is always a vanishingly scarce resource.&lt;/p&gt;

&lt;p&gt;8 - &lt;a href=&quot;#note-Tue-Mar-25-150547EDT-2014&quot; name=&quot;foot-Tue-Mar-25-150547EDT-2014&quot;&gt;[back]&lt;/a&gt; - Which isn&#39;t really final any more; I&#39;ve updated it several times since the stuff here.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/6470595176360528471/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2014/03/fact-base-indices.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/6470595176360528471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/6470595176360528471'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2014/03/fact-base-indices.html' title='Fact Base Indices'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-7659010190345318655</id><published>2014-03-20T16:55:00.000-07:00</published><updated>2014-03-29T08:11:52.665-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Bitching"/><category scheme="http://www.blogger.com/atom/ns#" term="Clojure"/><category scheme="http://www.blogger.com/atom/ns#" term="Common Lisp"/><category scheme="http://www.blogger.com/atom/ns#" term="Databases"/><category scheme="http://www.blogger.com/atom/ns#" term="Emacs"/><category scheme="http://www.blogger.com/atom/ns#" term="General Programming Thoughts"/><category scheme="http://www.blogger.com/atom/ns#" term="General Update"/><category scheme="http://www.blogger.com/atom/ns#" term="Journal"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming Environment"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming Interfaces"/><category scheme="http://www.blogger.com/atom/ns#" term="Speculation"/><title type='text'>Housekeeping</title><content type='html'>&lt;p&gt;Just some quick housekeeping while I draft up my next proper piece.&lt;/p&gt;

&lt;h3&gt;cl-cwd&lt;/h3&gt;

&lt;p&gt;A friend of mine mentioned that he had to hack up &lt;code&gt;cl-git-fs&lt;/code&gt; to make it export &lt;code&gt;cwd&lt;/code&gt; and &lt;code&gt;with-cwd&lt;/code&gt;. Which was surprising when I heard it, but really shouldn&#39;t have been. This is the sort of problem Common Lispers seem to solve by copy/pasting a few implementation-specific snippets into projects that need the functionality. That&#39;s not good enough for me. So, here&#39;s &lt;a href=&quot;https://github.com/Inaimathi/cl-cwd&quot;&gt;&lt;code&gt;cl-cwd&lt;/code&gt;&lt;/a&gt;; a library to get/manipulate/temporarily manipulate your current working directory in a cross-platform and cross-implementation way. Patches and bug reports welcome as always, and hopefully it&#39;s useful for you. I &lt;i&gt;haven&#39;t&lt;/i&gt; gotten around to hacking the same components out of &lt;code&gt;cl-git-fs&lt;/code&gt;, but I might eventually. Or, I might just use the &lt;code&gt;os&lt;/code&gt; section of &lt;a href=&quot;http://quickdocs.org/uiop/&quot;&gt;UIOP&lt;/a&gt;, which was only pointed out to me after I posted that &lt;code&gt;cl-cwd&lt;/code&gt; repo. I&#39;m not entirely sure what the right approach here is; are monolithic utility libraries preferable to very small, single-purpose packages? Not sure, but I kind of prefer the smaller, specific ones for my own purposes. Even though it never wastes enough resources to matter to me, it&#39;s deeply irritating on some level to include &lt;b&gt;all&lt;/b&gt; of &lt;a href=&quot;http://www.cliki.net/Alexandria&quot;&gt;&lt;code&gt;:alexandria&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;http://www.cliki.net/Anaphora&quot;&gt;&lt;code&gt;:anaphora&lt;/code&gt;&lt;/a&gt; for, essentially &lt;code&gt;with-gensyms&lt;/code&gt;, &lt;code&gt;aif&lt;/code&gt;, &lt;code&gt;awhen&lt;/code&gt; and &lt;code&gt;alambda&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;&lt;code&gt;fact-base&lt;/code&gt; updates and relevant minutia&lt;/h3&gt;

&lt;p&gt;I&#39;ve gotten some work done on &lt;a href=&quot;https://github.com/Inaimathi/fact-base&quot;&gt;&lt;code&gt;fact-base&lt;/code&gt;&lt;/a&gt;, which on reflection really should have been called &lt;code&gt;cl-triple-store&lt;/code&gt;, with an eye on using it in production. We&#39;ll see if it actually happens, or if it just remains an idle fancy, but&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;you can now add &lt;code&gt;index&lt;/code&gt;es to your fact bases, which should make data retrieval faster&lt;a href=&quot;#foot-Thu-Mar-20-195226EDT-2014&quot; name=&quot;note-Thu-Mar-20-195226EDT-2014&quot;&gt;[1]&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;writing deltas is now quite efficient&lt;a href=&quot;#foot-Thu-Mar-20-195230EDT-2014&quot; name=&quot;note-Thu-Mar-20-195230EDT-2014&quot;&gt;[2]&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Again, let me know if it&#39;s useful, or if it&#39;s sooooo-close-to-being-useful-if-it-only-had-this-one-feature. I might do something about it at this stage.&lt;/p&gt;

&lt;p&gt;The only related piece of minutia is that I&#39;ve found myself reading a lot about &lt;a href=&quot;http://minikanren.org/&quot;&gt;miniKanren&lt;/a&gt;, &lt;a href=&quot;https://github.com/clojure/core.logic&quot;&gt;core.logic&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Logic_programming&quot;&gt;logic programming&lt;/a&gt; in general. I &lt;i&gt;think&lt;/i&gt; it might be a really good way to query structures like these triple-stores I&#39;ve been building lately. Also, it turns out &lt;a href=&quot;http://common-lisp.net/project/cl-kanren-trs/&quot;&gt;someone&#39;s already done most of the work of implementing that in CL&lt;/a&gt; for me, so I &lt;a href=&quot;https://github.com/Inaimathi/cl-kanren-trs&quot;&gt;forked it&lt;/a&gt; and added/changed the few chunklets I needed to. Matthew Swank, if you&#39;re reading this and care, let me know and I&#39;ll send you patches. I assumed you wouldn&#39;t care, since the copyright line said &lt;code&gt;2008&lt;/code&gt;, but I might have been wrong.&lt;/p&gt;

&lt;h3&gt;Editors&lt;/h3&gt;

&lt;p&gt;Someone finally sat down and walked me through the installation for &lt;a href=&quot;http://www.lighttable.com/&quot;&gt;Light Table&lt;/a&gt;&lt;a href=&quot;#foot-Thu-Mar-20-195232EDT-2014&quot; name=&quot;note-Thu-Mar-20-195232EDT-2014&quot;&gt;[3]&lt;/a&gt;. I haven&#39;t been paying attention to the propaganda, so I&#39;m not entirely sure exactly how this is going to revolutionize editing&lt;a href=&quot;#foot-Thu-Mar-20-195235EDT-2014&quot; name=&quot;note-Thu-Mar-20-195235EDT-2014&quot;&gt;[4]&lt;/a&gt;, but it looks promising for a prototype. I was able to get to a productive-ish point with it within about an hour, and that&#39;s a high bar. I remember learning Emacs&lt;a href=&quot;#foot-Thu-Mar-20-195237EDT-2014&quot; name=&quot;note-Thu-Mar-20-195237EDT-2014&quot;&gt;[5]&lt;/a&gt; over the course of &lt;i&gt;weeks&lt;/i&gt;.&lt;/p&gt;

&lt;p&gt;Another one I tried enough to appreciate is &lt;a href=&quot;http://ipython.org/notebook.html&quot;&gt;IPython Notebook&lt;/a&gt;. The idea of a browser-based editor has, shall we say, &lt;a href=&quot;http://langnostic.blogspot.ca/2014/01/update-and-finer-points-of-quasimodes.html&quot;&gt;crossed my mind&lt;/a&gt;, but the idea of applying it to 1D coding hadn&#39;t occurred to me. I gotta say, I like the idea, and I&#39;ll be trying to do something about that right &lt;a href=&quot;https://github.com/Inaimathi/cl-notebook&quot;&gt;here&lt;/a&gt;. I&#39;ve only got the easy part done so far; a front-end of &lt;a href=&quot;http://codemirror.net/&quot;&gt;code-mirror&lt;/a&gt; rigged up to a Lisp process that evaluates things and sends the result values back&lt;a href=&quot;#foot-Thu-Mar-20-195240EDT-2014&quot; name=&quot;note-Thu-Mar-20-195240EDT-2014&quot;&gt;[6]&lt;/a&gt;. The hard part is going to involve a persistence layer, multiple cells, multiple notebooks and probably some smaller browsing/presentation/generation features to let me do whatever&lt;a href=&quot;#foot-Thu-Mar-20-195242EDT-2014&quot; name=&quot;note-Thu-Mar-20-195242EDT-2014&quot;&gt;[7]&lt;/a&gt;. Spoiler warning: &lt;a href=&quot;https://github.com/Inaimathi/fact-base&quot;&gt;&lt;code&gt;fact-base&lt;/code&gt;&lt;/a&gt; and its history/indexing operations will feature prominently. The ultimate goal is no less than replacing Emacs as my Common Lisp IDE of choice.&lt;/p&gt;

&lt;p&gt;And that&#39;s sort of why I&#39;ve been on another editor/tools kick lately.&lt;/p&gt;

&lt;p&gt;I&#39;ve been talking to some friends in the local programming community, and we seem to have collectively decided that we really, &lt;i&gt;really&lt;/i&gt; want Light Table to succeed because it sucks not being able to recommend anything as a starting tool for Common Lisp development to programming newbies. Our options right now are what can charitably be referred to as &lt;a href=&quot;https://www.gnu.org/software/emacs/&quot;&gt;a very intimidating operating system/rss aggregator/IRC client/moustache trimmer&lt;/a&gt;&lt;a href=&quot;#foot-Thu-Mar-20-195245EDT-2014&quot; name=&quot;note-Thu-Mar-20-195245EDT-2014&quot;&gt;[8]&lt;/a&gt;, &lt;a href=&quot;https://www.eclipse.org/&quot;&gt;a &lt;i&gt;wannabe&lt;/i&gt; very intimidating blah blah blah&lt;/a&gt;, &lt;a href=&quot;http://www.sublimetext.com/&quot;&gt;a very pretty, passably comfortable pair of handcuffs&lt;/a&gt;, &lt;a href=&quot;http://www.lispworks.com/&quot;&gt;a very performant, robust, ridiculously expensive pair of handcuffs&lt;/a&gt;, and &lt;a href=&quot;http://stackoverflow.com/questions/94792/using-vim-for-lisp-development&quot;&gt;vim&lt;/a&gt;. If you&#39;re recommending Scheme, there&#39;s also &lt;a href=&quot;http://www.racket-lang.org/&quot;&gt;Racket&lt;/a&gt;&lt;a href=&quot;#foot-Thu-Mar-20-195247EDT-2014&quot; name=&quot;note-Thu-Mar-20-195247EDT-2014&quot;&gt;[9]&lt;/a&gt;, but that still doesn&#39;t count as a Common Lisp environment.&lt;/p&gt;

&lt;p&gt;Some of those are things I&#39;d recommend to people who are already programmers. One of them is something that I&#39;d recommend to people looking to learn languages for the sake of learning them. But there isn&#39;t a tool anywhere on that list that compares to something like &lt;a href=&quot;http://docs.python.org/2/library/idle.html&quot;&gt;Idle&lt;/a&gt; or, more to the point, &lt;a href=&quot;http://www.lighttable.com/&quot;&gt;Light Table&lt;/a&gt;. I don&#39;t think it&#39;s quite at the point where I&#39;d switch over to it myself, but I sincerely hope it gets there. And I&#39;ll be devoting some effort to pushing that along. You can too, &lt;a href=&quot;https://github.com/LightTable/LightTable&quot;&gt;since it&#39;s up&lt;/a&gt; and &lt;a href=&quot;https://github.com/LightTable/LightTable/blob/master/LICENSE.md#gnu-general-public-license&quot;&gt;properly licensed&lt;/a&gt; and all...&lt;/p&gt;


&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Thu-Mar-20-195226EDT-2014&quot; name=&quot;foot-Thu-Mar-20-195226EDT-2014&quot;&gt;[back]&lt;/a&gt; - There&#39;s an article either in the works or already posted, depending on what order I decide to put these up.&lt;/p&gt;
&lt;p&gt;2 - &lt;a href=&quot;#note-Thu-Mar-20-195230EDT-2014&quot; name=&quot;foot-Thu-Mar-20-195230EDT-2014&quot;&gt;[back]&lt;/a&gt; - From a macro-optimization perspective; I&#39;m sure I could pull some micro-optimizations on it too, but I&#39;m not into that.&lt;/p&gt;
&lt;p&gt;3 - &lt;a href=&quot;#note-Thu-Mar-20-195232EDT-2014&quot; name=&quot;foot-Thu-Mar-20-195232EDT-2014&quot;&gt;[back]&lt;/a&gt; - Turns out that even the &lt;a href=&quot;https://packages.debian.org/sid/leiningen&quot;&gt;Debian Unstable&lt;/a&gt; repo doesn&#39;t have a recent enough version of &lt;a href=&quot;https://github.com/technomancy/leiningen&quot;&gt;Leiningen&lt;/a&gt;. I needed to latest using &lt;a href=&quot;https://raw.github.com/technomancy/leiningen/stable/bin/lein&quot;&gt;this&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;4 - &lt;a href=&quot;#note-Thu-Mar-20-195235EDT-2014&quot; name=&quot;foot-Thu-Mar-20-195235EDT-2014&quot;&gt;[back]&lt;/a&gt; - In fact, the only visible revolutionization of &quot;randomly putting shit in your buffers that you can&#39;t edit instead of giving you a goddamn REPL&quot;, is profoundly annoying, though it&#39;s possible to disagree about these things. I guess I can imagine it looking really snazzy in presentations and demo videos.&lt;/p&gt;
&lt;p&gt;5 - &lt;a href=&quot;#note-Thu-Mar-20-195237EDT-2014&quot; name=&quot;foot-Thu-Mar-20-195237EDT-2014&quot;&gt;[back]&lt;/a&gt; - ...and before that jEdit, and before that Eclipse.&lt;/p&gt;
&lt;p&gt;6 - &lt;a href=&quot;#note-Thu-Mar-20-195240EDT-2014&quot; name=&quot;foot-Thu-Mar-20-195240EDT-2014&quot;&gt;[back]&lt;/a&gt; - And yes, it handles multiple values as well as &lt;code&gt;*standard-output*&lt;/code&gt; emissions, in case you were wondering.&lt;/p&gt;
&lt;p&gt;7 - &lt;a href=&quot;#note-Thu-Mar-20-195242EDT-2014&quot; name=&quot;foot-Thu-Mar-20-195242EDT-2014&quot;&gt;[back]&lt;/a&gt; - At minimum the possibility to write &lt;code&gt;:cl-who&lt;/code&gt;/&lt;code&gt;:cl-css&lt;/code&gt; instead of markdown, a way of installing libraries that doesn&#39;t go through quicklisp, and maybe some git/&lt;a href=&quot;https://github.com/edicl/drakma&quot;&gt;drakma&lt;/a&gt;/shell support. I may end up having to add non-shitty static file serving to &lt;code&gt;house&lt;/code&gt; for this...&lt;/p&gt;
&lt;p&gt;8 - &lt;a href=&quot;#note-Thu-Mar-20-195245EDT-2014&quot; name=&quot;foot-Thu-Mar-20-195245EDT-2014&quot;&gt;[back]&lt;/a&gt; - &lt;a href=&quot;http://common-lisp.net/project/lispbox/&quot;&gt;Pre-built Lisp IDE version&lt;/a&gt; optional.&lt;/p&gt;
&lt;p&gt;9 - &lt;a href=&quot;#note-Thu-Mar-20-195247EDT-2014&quot; name=&quot;foot-Thu-Mar-20-195247EDT-2014&quot;&gt;[back]&lt;/a&gt; - Which I do wholeheartedly recommend; it&#39;s very cool.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/7659010190345318655/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2014/03/housekeeping.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/7659010190345318655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/7659010190345318655'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2014/03/housekeeping.html' title='Housekeeping'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-8041249070390384777</id><published>2014-03-06T09:11:00.001-08:00</published><updated>2014-03-06T09:12:07.716-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Daimio"/><category scheme="http://www.blogger.com/atom/ns#" term="Elm"/><category scheme="http://www.blogger.com/atom/ns#" term="Flow Based Programming"/><title type='text'>Flow-Based Games</title><content type='html'>&lt;p&gt;So I just tried to write what I thought was a fairly simple game prototype tentatively titled &quot;Gratuitous Resource Gathering&quot; using &lt;a href=&quot;http://elm-lang.org/&quot;&gt;Elm&lt;/a&gt;. Something in the style of &lt;a href=&quot;http://orteil.dashnet.org/cookieclicker/&quot;&gt;Cookie Clicker&lt;/a&gt;(DO NOT click that link if you were planning on doing anything today). Here&#39;s how far I got:&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Mouse&lt;/span&gt;
&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Time&lt;/span&gt;

&lt;span style=&quot;color: #0000ff;&quot;&gt;port&lt;/span&gt; resourceA &lt;span style=&quot;color: #228b22;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Signal&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Bool&lt;/span&gt;
&lt;span style=&quot;color: #0000ff;&quot;&gt;port&lt;/span&gt; building &lt;span style=&quot;color: #228b22;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Signal&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;

&lt;span style=&quot;color: #0000ff;&quot;&gt;buildingCost&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; foldp (&lt;span style=&quot;color: #a0522d;&quot;&gt;+&lt;/span&gt;) 0 &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; keepWhen (lift2 (&lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;gt;&lt;/span&gt;) (constant 50) balance) 0 &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; sampleOn building &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; constant 50

&lt;span style=&quot;color: #0000ff;&quot;&gt;tickIncrement&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; foldp (&lt;span style=&quot;color: #a0522d;&quot;&gt;+&lt;/span&gt;) 0 &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; sampleOn buildingCost &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; constant 0&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;01
&lt;span style=&quot;color: #0000ff;&quot;&gt;tick&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; sampleOn (every &lt;span style=&quot;color: #228b22;&quot;&gt;Time&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;millisecond) &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; constant &lt;span style=&quot;color: #228b22;&quot;&gt;True&lt;/span&gt;

&lt;span style=&quot;color: #0000ff;&quot;&gt;spent&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; foldp (&lt;span style=&quot;color: #a0522d;&quot;&gt;+&lt;/span&gt;) 0 &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; merges [ sampleOn building buildingCost ]

&lt;span style=&quot;color: #0000ff;&quot;&gt;gathered&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; foldp (&lt;span style=&quot;color: #a0522d;&quot;&gt;+&lt;/span&gt;) 0 &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; merges [ sampleOn resourceA &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; constant 1
                                 , sampleOn tick tickIncrement ]

&lt;span style=&quot;color: #0000ff;&quot;&gt;balance&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; lift round &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; lift2 (&lt;span style=&quot;color: #a0522d;&quot;&gt;-&lt;/span&gt;) gathered spent

&lt;span style=&quot;color: #0000ff;&quot;&gt;main&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; lift (flow down) &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; combine [ lift asText balance ]&lt;/pre&gt;

&lt;p&gt;That&#39;s almost the complete game, except for one very annoying detail: it doesn&#39;t work. When I try to run it in the appropriate HTML harness, I get&lt;/p&gt;

&lt;pre&gt;s2 is undefined
    Open the developer console for more details.&lt;/pre&gt;

&lt;p&gt;The reason is that &lt;code&gt;buildingCost&lt;/code&gt; signal. When the user purchases a building, I need to check whether they have enough resource balance to buy it. However, the &lt;code&gt;balance&lt;/code&gt; is the sum of two other signals, &lt;code&gt;gathered&lt;/code&gt; and &lt;code&gt;spent&lt;/code&gt;, the second of which &lt;i&gt;is affected by building purchases&lt;/i&gt;. Looks like circular signals aren&#39;t a thing in Elm right now. I&#39;m not sure how to resolve this inside the language, and I already told you all about ports last time, so my natural first reaction was to think about how I&#39;d go about computing that price check outside the Elm module. Unfortunately, once I started mentally pulling things out of Elm, I quickly arrived at the conclusion that the whole thing would probably need to be turned inside-out. In other words, I&#39;d be using Elm purely as a way of avoiding manual DOM manipulation in one or two components of a mostly Javascript project.&lt;/p&gt;

&lt;p&gt;Maybe that&#39;d still be worth it, but it feels quite unsatisfying.&lt;/p&gt;

&lt;p&gt;No real idea what to do about it though. I&#39;ll talk to some people I consider smarter than me and see what they think. Hopefully there&#39;s a reasonable way around the problem that doesn&#39;t include doing most of it in manual JS.&lt;/p&gt;

&lt;p&gt;In the meantime, I hacked together something in &lt;a href=&quot;https://github.com/dxnn/daimio&quot;&gt;Daimio&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;outer
        @resource-click dom-on-click resource
        @building-click dom-on-click building
        @show dom-set-html display

        @timer every-half-second

        $building-cost 5
        $click-increment 1
        $tick-increment 0
        $balance 0

        inc-balance 
                { __ | add $balance | &amp;gt;$balance }
        dec-balance 
                { __ | subtract value __ from $balance | &amp;gt;$balance }

        can-afford
                { __ | ($building-cost $balance) | max | eq $balance }
        
        @resource-click -&amp;gt; {__ | $click-increment } -&amp;gt; inc-balance -&amp;gt; @show
        @building-click -&amp;gt; can-afford -&amp;gt; { __ | then $building-cost else 0} -&amp;gt; dec-balance -&amp;gt; @show
                           can-afford -&amp;gt; { __ | then 10 else 0 | add $tick-increment | &amp;gt;$tick-increment }
                           can-afford -&amp;gt; { __ | then &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Buying...&quot;&lt;/span&gt; | tap }

        @timer -&amp;gt; {__ | $tick-increment } -&amp;gt; inc-balance -&amp;gt; { __ | $balance } -&amp;gt;  @show&lt;/pre&gt;

&lt;p&gt;No highlighting mode for that one yet; I&#39;m workin&#39; on it. Also, the above was kind of non-trivial because I had to add my own timer event, &lt;i&gt;and&lt;/i&gt; I still want to figure out how to factor out the process of buying a building. But it works well enough on my machine. I&#39;ll post the full project up to my &lt;a href=&quot;https://github.com/Inaimathi&quot;&gt;github&lt;/a&gt; once I do a bit more thinking about it.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/8041249070390384777/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2014/03/flow-based-games.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/8041249070390384777'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/8041249070390384777'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2014/03/flow-based-games.html' title='Flow-Based Games'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-982376221181944036</id><published>2014-02-17T12:07:00.001-08:00</published><updated>2014-02-25T07:04:18.359-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Almost Literate Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="Elm"/><category scheme="http://www.blogger.com/atom/ns#" term="Flow Based Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="HTML"/><title type='text'>Autocompletion Example with Ports in Elm</title><content type='html'>&lt;p&gt;Two things on the agenda today. First, Elm has gotten some improvements that might mean I end up using it in production at some point. Second, I tried a new language called &lt;a href=&quot;http://purelang.bitbucket.org/&quot;&gt;Pure&lt;/a&gt;, which I found by searching for &quot;dynamically typed haskell&quot;. Stick around if that sounds interesting.&lt;/p&gt;

&lt;span class=&quot;edit&quot;&gt;EDIT:
&lt;p&gt;Do not bother sticking around if that sounds interesting. I ended up talking about Elm so much that I never got into Pure.&lt;/p&gt;

Tue, 18 Feb, 2014&lt;/span&gt;

&lt;h3&gt;Elm Lang&lt;/h3&gt;

&lt;p&gt;For those of you just joining us, &lt;a href=&quot;http://elm-lang.org/&quot;&gt;Elm&lt;/a&gt; is a pure-functional, statically typed, optionally-type-inferring language closely based on &lt;a href=&quot;http://www.haskell.org/haskellwiki/Haskell&quot;&gt;Haskell&lt;/a&gt;, which targets a JavaScript-hosted VM for deployment. That is, there&#39;s an &lt;code&gt;elm-runtime.js&lt;/code&gt; which Elm code compiles to target, and the result is highly reactive web front-ends that don&#39;t require any mucking around with the DOM. Now that we&#39;re all on the same page...&lt;/p&gt;

&lt;h3&gt;Elm. Again.&lt;/h3&gt;

&lt;p&gt;This came up at a recent &lt;a href=&quot;https://bentomiso.com/events/toronto-code-retreat-2014-feb&quot;&gt;Code Retreat&lt;/a&gt;, and it looks interesting as fuck in context with the FBP stuff I&#39;ve been doing at work recently. The problem we were solving at the event was autocompletion. That is, given a partial input, return possible completions from some dictionary. Here&#39;s a short&lt;a href=&quot;#foot-Mon-Feb-17-150009EST-2014&quot; name=&quot;note-Mon-Feb-17-150009EST-2014&quot;&gt;[1]&lt;/a&gt; implementation in Elm.&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #a020f0;&quot;&gt;module&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Autocomplete&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;where&lt;/span&gt;

&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;
&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Keyboard&lt;/span&gt;
&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Graphics.Input&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;as&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Input&lt;/span&gt;

(field, content) &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;field &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Enter text&quot;&lt;/span&gt;

fState &lt;span style=&quot;color: #0000ff;&quot;&gt;:&lt;/span&gt; [&lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;] &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Input.FieldState&lt;/span&gt;
&lt;span style=&quot;color: #0000ff;&quot;&gt;fState&lt;/span&gt; comps &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;case&lt;/span&gt; comps &lt;span style=&quot;color: #a020f0;&quot;&gt;of&lt;/span&gt;
                 &lt;span style=&quot;color: #228b22;&quot;&gt;[]&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; {string &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;&quot;&lt;/span&gt;, selectionStart&lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt;0, selectionEnd&lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt;0}
                 &lt;span style=&quot;color: #a020f0;&quot;&gt;_&lt;/span&gt;  &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; {string &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; (head comps), selectionStart&lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt;0, selectionEnd&lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt;0}

&lt;span style=&quot;color: #0000ff;&quot;&gt;esc&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Keyboard&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;isDown 27
&lt;span style=&quot;color: #0000ff;&quot;&gt;ctrlSpace&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; dropRepeats &lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt; lift and &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; combine [&lt;span style=&quot;color: #228b22;&quot;&gt;Keyboard&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;ctrl, &lt;span style=&quot;color: #228b22;&quot;&gt;Keyboard&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;space]

empty &lt;span style=&quot;color: #0000ff;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Signal&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Element&lt;/span&gt;
&lt;span style=&quot;color: #0000ff;&quot;&gt;empty&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; sampleOn (merge &lt;span style=&quot;color: #228b22;&quot;&gt;Keyboard&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;enter esc) &lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt; fst &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;field &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Enter text&quot;&lt;/span&gt;

completeElem &lt;span style=&quot;color: #0000ff;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Signal&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Element&lt;/span&gt;
&lt;span style=&quot;color: #0000ff;&quot;&gt;completeElem&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; lift ((&lt;span style=&quot;color: #228b22;&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;fields &lt;span style=&quot;color: #228b22;&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;emptyFieldState)&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;field id &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Enter text&quot;&lt;/span&gt;) &lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt; sampleOn ctrlSpace &lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt; lift fState &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; lift completions content

completions &lt;span style=&quot;color: #0000ff;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; [&lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;]
&lt;span style=&quot;color: #0000ff;&quot;&gt;completions&lt;/span&gt; partial &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;|&lt;/span&gt; 0 &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;length partial &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; filter (&lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;startsWith partial) wordList
                         &lt;span style=&quot;color: #a0522d;&quot;&gt;|&lt;/span&gt; otherwise          &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;[]&lt;/span&gt;

&lt;span style=&quot;color: #0000ff;&quot;&gt;main&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; lift2 above (merges [field, completeElem, empty]) &lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt; lift asText &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; lift completions content

&lt;span style=&quot;color: #b22222;&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;- Dummy data
&lt;/span&gt;wordList &lt;span style=&quot;color: #0000ff;&quot;&gt;:&lt;/span&gt; [&lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;]
&lt;span style=&quot;color: #0000ff;&quot;&gt;wordList&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;words &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;one two three four five six seven eight nine ten&quot;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The point here is: there&#39;s an input that displays completions as you type. If you hit the &lt;code&gt;enter&lt;/code&gt; or &lt;code&gt;esc&lt;/code&gt; keys, that input is cleared, and if you hit &lt;code&gt;Ctrl+Space&lt;/code&gt;, it&#39;s filled with the top completion. The above doesn&#39;t let you select a different completion, which it should, but it&#39;s a pretty instructive example.&lt;/p&gt;

&lt;p&gt;Lets go through it.&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #a020f0;&quot;&gt;module&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Autocomplete&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;where&lt;/span&gt;

&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;
&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Keyboard&lt;/span&gt;
&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Graphics.Input&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;as&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Input&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Module and import declarations. Nothing to see here, move along.&lt;/p&gt;

&lt;pre&gt;(field, content) &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;field &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Enter text&quot;&lt;/span&gt;

fState &lt;span style=&quot;color: #0000ff;&quot;&gt;:&lt;/span&gt; [&lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;] &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Input.FieldState&lt;/span&gt;
&lt;span style=&quot;color: #0000ff;&quot;&gt;fState&lt;/span&gt; comps &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;case&lt;/span&gt; comps &lt;span style=&quot;color: #a020f0;&quot;&gt;of&lt;/span&gt;
                 &lt;span style=&quot;color: #228b22;&quot;&gt;[]&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; {string &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;&quot;&lt;/span&gt;, selectionStart&lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt;0, selectionEnd&lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt;0}
                 &lt;span style=&quot;color: #a020f0;&quot;&gt;_&lt;/span&gt;  &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; {string &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; (head comps), selectionStart&lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt;0, selectionEnd&lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt;(&lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;length &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; head comps)}&lt;/pre&gt;

&lt;p&gt;The first line in this bit sets up a &lt;code&gt;field&lt;/code&gt;, which is represented as a pair of &lt;code&gt;Signal&lt;/code&gt;s; one for the element and one for the content. Signals are a pretty good way of modeling state changes over time in a purely-functional context. You can think of one as the infinite stream of possible values it&#39;ll contain, the current of which your program will be continuously operating. An input &lt;code&gt;field&lt;/code&gt; is a &lt;i&gt;pair&lt;/i&gt; of signals because you&#39;d like to be able to change it&lt;a href=&quot;#foot-Mon-Feb-17-150016EST-2014&quot; name=&quot;note-Mon-Feb-17-150016EST-2014&quot;&gt;[2]&lt;/a&gt;, as well as receive updates about its state changes. We&#39;ll do that by combining several signals on particular sample points, and &lt;code&gt;FieldState&lt;/code&gt; is the type we can eventually funnel into a field.&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;esc&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Keyboard&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;isDown 27
&lt;span style=&quot;color: #0000ff;&quot;&gt;ctrlSpace&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; dropRepeats &lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt; lift and &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; combine [&lt;span style=&quot;color: #228b22;&quot;&gt;Keyboard&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;ctrl, &lt;span style=&quot;color: #228b22;&quot;&gt;Keyboard&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;space]&lt;/pre&gt;

&lt;p&gt;These represent two different signals we&#39;d like from the &lt;code&gt;Keyboard&lt;/code&gt; module. The first will be &lt;code&gt;True&lt;/code&gt; whenever the Escape key is down&lt;a href=&quot;#foot-Mon-Feb-17-150022EST-2014&quot; name=&quot;note-Mon-Feb-17-150022EST-2014&quot;&gt;[3]&lt;/a&gt;, the second will be &lt;code&gt;True&lt;/code&gt; when both the &lt;code&gt;Ctrl&lt;/code&gt; and &lt;code&gt;Space&lt;/code&gt; key are pressed&lt;a href=&quot;#foot-Mon-Feb-17-150025EST-2014&quot; name=&quot;note-Mon-Feb-17-150025EST-2014&quot;&gt;[4]&lt;/a&gt;. The types at each step might be useful. In particular, &lt;code&gt;ctrlSpace : Signal Bool&lt;/code&gt;, &lt;code&gt;combine &lt;span style=&quot;color: #0000ff;&quot;&gt;:&lt;/span&gt; [&lt;span style=&quot;color: #228b22;&quot;&gt;Signal&lt;/span&gt; a] &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Signal&lt;/span&gt; [a]&lt;/code&gt; and &lt;code&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;lift&lt;/span&gt; and &lt;span style=&quot;color: #228b22;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Signal&lt;/span&gt; [&lt;span style=&quot;color: #228b22;&quot;&gt;Bool&lt;/span&gt;] &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Signal&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Bool&lt;/span&gt;&lt;/code&gt;. The &lt;code&gt;dropRepeats&lt;/code&gt; is the only chunklet whose type signature will give you no further understanding &lt;a href=&quot;#foot-Mon-Feb-17-150223EST-2014&quot; name=&quot;note-Mon-Feb-17-150223EST-2014&quot;&gt;[5]&lt;/a&gt;; it&#39;s there to prevent partial signal changes from triggering a &quot;change&quot; in the &lt;code&gt;ctrlSpace&lt;/code&gt; signal itself. Also, on a syntax note, the &lt;code&gt;&amp;lt;|&lt;/code&gt; is identical to &lt;a href=&quot;http://stackoverflow.com/a/1290727/190887&quot;&gt;Haskell&#39;s $&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Onward.&lt;/p&gt;

&lt;pre&gt;empty &lt;span style=&quot;color: #0000ff;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Signal&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Element&lt;/span&gt;
&lt;span style=&quot;color: #0000ff;&quot;&gt;empty&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; sampleOn (merge &lt;span style=&quot;color: #228b22;&quot;&gt;Keyboard&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;enter esc) &lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt; fst &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;field &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Enter text&quot;&lt;/span&gt;

completeElem &lt;span style=&quot;color: #0000ff;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Signal&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Element&lt;/span&gt;
&lt;span style=&quot;color: #0000ff;&quot;&gt;completeElem&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; lift ((&lt;span style=&quot;color: #228b22;&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;fields &lt;span style=&quot;color: #228b22;&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;emptyFieldState)&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;field id &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Enter text&quot;&lt;/span&gt;) &lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt; sampleOn ctrlSpace &lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt; lift fState &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; lift completions content

completions &lt;span style=&quot;color: #0000ff;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; [&lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;]
&lt;span style=&quot;color: #0000ff;&quot;&gt;completions&lt;/span&gt; partial &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;|&lt;/span&gt; 0 &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;length partial &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; filter (&lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;startsWith partial) wordList
                         &lt;span style=&quot;color: #a0522d;&quot;&gt;|&lt;/span&gt; otherwise          &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;[]&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;This is the real meat right here. &lt;code&gt;empty&lt;/code&gt; is the signal of empty elements which will &quot;changes&quot; whenever the &lt;code&gt;enter&lt;/code&gt; or &lt;code&gt;esc&lt;/code&gt; keys are pressed&lt;a href=&quot;#foot-Mon-Feb-17-150245EST-2014&quot; name=&quot;note-Mon-Feb-17-150245EST-2014&quot;&gt;[6]&lt;/a&gt;. &lt;code&gt;completeElem&lt;/code&gt; is the signal of filled elements that &quot;changes&quot; whenever the user hits &lt;code&gt;Ctrl + Space&lt;/code&gt;. Finally, &lt;code&gt;completions&lt;/code&gt; is the signal of completions of the current text in the main input.&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;main&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; lift2 above (merges [field, completeElem, empty]) &lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt; lift asText &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; lift completions content

&lt;span style=&quot;color: #b22222;&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;- Dummy data
&lt;/span&gt;wordList &lt;span style=&quot;color: #0000ff;&quot;&gt;:&lt;/span&gt; [&lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;]
&lt;span style=&quot;color: #0000ff;&quot;&gt;wordList&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;words &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;one two three four five six seven eight nine ten&quot;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;These remaining lines render the input and completions to screen, and set up the extremely minimal test dictionary. That&#39;s it. What we have here is exactly what was described. An input, backed by a word list, which is cleared on either Enter or Esc, and completed on Ctrl+Space.&lt;/p&gt;

&lt;h3&gt;The New Part&lt;/h3&gt;

&lt;p&gt;None of that was new.&lt;/p&gt;

&lt;p&gt;If you&#39;ve read any of the articles on this blog tagged Elm, you&#39;d have known all of it already. The new part is that you can now have your Elm programs communicate with the outside world. In the case we&#39;re considering above, a solitary auto-completing input is pretty useless. But imagine if you could use it essentially as a minibuffer in a larger project. You&#39;d want to be able to pass it new completion lists, and you&#39;d want it to notify you when the user entered some input. It goes without saying that you&#39;d like all this to be encapsulated within a known, non-global namespace, so that you could combine your Elm minibuffer with arbitrary JS projects.&lt;/p&gt;

&lt;p&gt;So, lets do it.&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #a020f0;&quot;&gt;module&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Autocomplete&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;where&lt;/span&gt;

&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;
&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Keyboard&lt;/span&gt;
&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Graphics.Input&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;as&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Input&lt;/span&gt;

(field, content) &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;field &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Enter text&quot;&lt;/span&gt;

fState &lt;span style=&quot;color: #0000ff;&quot;&gt;:&lt;/span&gt; [&lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;] &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Input.FieldState&lt;/span&gt;
&lt;span style=&quot;color: #0000ff;&quot;&gt;fState&lt;/span&gt; comps &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;case&lt;/span&gt; comps &lt;span style=&quot;color: #a020f0;&quot;&gt;of&lt;/span&gt;
                 &lt;span style=&quot;color: #228b22;&quot;&gt;[]&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; {string &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;&quot;&lt;/span&gt;, selectionStart&lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt;0, selectionEnd&lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt;0}
                 &lt;span style=&quot;color: #a020f0;&quot;&gt;_&lt;/span&gt;  &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; {string &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; (head comps), selectionStart&lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt;0, selectionEnd&lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; (&lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;length &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; head comps)}

&lt;span style=&quot;color: #0000ff;&quot;&gt;esc&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Keyboard&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;isDown 27
&lt;span style=&quot;color: #0000ff;&quot;&gt;ctrlSpace&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; dropRepeats &lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt; lift and &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; combine [&lt;span style=&quot;color: #228b22;&quot;&gt;Keyboard&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;ctrl, &lt;span style=&quot;color: #228b22;&quot;&gt;Keyboard&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;space]

empty &lt;span style=&quot;color: #0000ff;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Signal&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Element&lt;/span&gt;
&lt;span style=&quot;color: #0000ff;&quot;&gt;empty&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; sampleOn (merge &lt;span style=&quot;color: #228b22;&quot;&gt;Keyboard&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;enter esc) &lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt; fst &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;field &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Enter text&quot;&lt;/span&gt;

completeElem &lt;span style=&quot;color: #0000ff;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Signal&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Element&lt;/span&gt;
&lt;span style=&quot;color: #0000ff;&quot;&gt;completeElem&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; lift ((&lt;span style=&quot;color: #228b22;&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;fields &lt;span style=&quot;color: #228b22;&quot;&gt;Input&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;emptyFieldState)&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;field id &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Enter text&quot;&lt;/span&gt;) &lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt; sampleOn ctrlSpace &lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt; lift fState &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; lift2 completions content wordList

completions &lt;span style=&quot;color: #0000ff;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; [&lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;] &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; [&lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;]
&lt;span style=&quot;color: #0000ff;&quot;&gt;completions&lt;/span&gt; partial wordList &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;|&lt;/span&gt; 0 &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;length partial &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; filter (&lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;startsWith partial) wordList
                                  &lt;span style=&quot;color: #a0522d;&quot;&gt;|&lt;/span&gt; otherwise          &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;[]&lt;/span&gt;

&lt;span style=&quot;color: #0000ff;&quot;&gt;main&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; lift2 above (merges [field, completeElem, empty]) &lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt; lift asText &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; lift2 completions content wordList

&lt;span style=&quot;color: #0000ff;&quot;&gt;port&lt;/span&gt; wordList &lt;span style=&quot;color: #228b22;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Signal&lt;/span&gt; [&lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;]

&lt;span style=&quot;color: #0000ff;&quot;&gt;port&lt;/span&gt; output &lt;span style=&quot;color: #228b22;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Signal&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt;
&lt;span style=&quot;color: #0000ff;&quot;&gt;port&lt;/span&gt; output &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; keepIf (&lt;span style=&quot;color: #a0522d;&quot;&gt;\&lt;/span&gt;s &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; s&lt;span style=&quot;color: #a0522d;&quot;&gt;/=&lt;/span&gt;&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;&quot;&lt;/span&gt;) &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;&quot;&lt;/span&gt; (sampleOn &lt;span style=&quot;color: #228b22;&quot;&gt;Keyboard&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;enter content)&lt;/pre&gt;

&lt;p&gt;That&#39;s a minimally changed &lt;code&gt;.elm&lt;/code&gt; file. The differences are&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We&#39;ve added port declarations at the bottom there. One incoming, which is just a type declaration, and one outgoing, which has a type declaration and a transmitter function.&lt;/li&gt;
  &lt;li&gt;We&#39;ve changed &lt;code&gt;completions&lt;/code&gt; so that it takes its &lt;code&gt;wordList&lt;/code&gt; as input&lt;/li&gt;
  &lt;li&gt;Anywhere we used to call &lt;code&gt;completions&lt;/code&gt; with &lt;code&gt;lift completions content&lt;/code&gt;, we now have to call it with &lt;code&gt;lift2 completions content wordList&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The file you&#39;d embed that module into would look something like this&lt;a href=&quot;#foot-Mon-Feb-17-150258EST-2014&quot; name=&quot;note-Mon-Feb-17-150258EST-2014&quot;&gt;[7]&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;&amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;html&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;xmlns&lt;/span&gt;=&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;http://www.w3.org/1999/xhtml&quot;&lt;/span&gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;xml&lt;/span&gt;:&lt;span style=&quot;color: #a0522d;&quot;&gt;lang&lt;/span&gt;=&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;en&quot;&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;lang&lt;/span&gt;=&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;en&quot;&lt;/span&gt;&amp;gt;
  &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;head&lt;/span&gt;&amp;gt;
    &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;title&lt;/span&gt;&amp;gt;&lt;span style=&quot;font-weight: bold; text-decoration: underline;&quot;&gt;Embedding Autocomplete - Elm&lt;/span&gt;&amp;lt;/&lt;span style=&quot;color: #0000ff;&quot;&gt;title&lt;/span&gt;&amp;gt;
    &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;script&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;type&lt;/span&gt;=&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;src&lt;/span&gt;=&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;/elm-runtime.js&quot;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&quot;color: #0000ff;&quot;&gt;script&lt;/span&gt;&amp;gt;
    &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;script&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;type&lt;/span&gt;=&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;src&lt;/span&gt;=&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;/build/Autocomplete.js&quot;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&quot;color: #0000ff;&quot;&gt;script&lt;/span&gt;&amp;gt;
  &amp;lt;/&lt;span style=&quot;color: #0000ff;&quot;&gt;head&lt;/span&gt;&amp;gt;
  &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;body&lt;/span&gt;&amp;gt;
    &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;div&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;id&lt;/span&gt;=&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;auto&quot;&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;style&lt;/span&gt;=&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;position: absolute; left: 50px; top: 50px; width: 600px; height: 100px; border: 2px dashed #000;&quot;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&quot;color: #0000ff;&quot;&gt;div&lt;/span&gt;&amp;gt;
    &amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;script&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;type&lt;/span&gt;=&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&amp;gt;
      var can = Elm.embed(Elm.Autocomplete, 
                          document.getElementById(&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;auto&quot;&lt;/span&gt;), 
                          {wordList: [&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;one&quot;&lt;/span&gt;, &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;two&quot;&lt;/span&gt;, &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;three&quot;&lt;/span&gt;, &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;four&quot;&lt;/span&gt;, &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;five&quot;&lt;/span&gt;, &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;six&quot;&lt;/span&gt;, &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;seven&quot;&lt;/span&gt;, &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;eight&quot;&lt;/span&gt;, &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;nine&quot;&lt;/span&gt;, &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;ten&quot;&lt;/span&gt;]});
      can.ports.output.subscribe(function (msg) { console.log(&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;FROM MINIBUFFER :: &quot;&lt;/span&gt;, msg) })
    &amp;lt;/&lt;span style=&quot;color: #0000ff;&quot;&gt;script&lt;/span&gt;&amp;gt;
  &amp;lt;/&lt;span style=&quot;color: #0000ff;&quot;&gt;body&lt;/span&gt;&amp;gt;
&amp;lt;/&lt;span style=&quot;color: #0000ff;&quot;&gt;html&lt;/span&gt;&amp;gt;&lt;/pre&gt;

&lt;span class=&quot;edit&quot;&gt;EDIT:

&lt;p&gt;You can find a running demo of the above &lt;a href=&quot;http://173.255.226.138/elm-sample/embed.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
Sat, 22 Feb, 2014&lt;/span&gt;

&lt;p&gt;The relevant bits are the positioned &lt;code&gt;div&lt;/code&gt;, which will contain our program, and the &lt;code&gt;Elm.embed&lt;/code&gt; call, which sets it up. Note especially the third argument; you have to do that for any input ports in the component you&#39;re embedding. Finally, note the &lt;code&gt;subscribe&lt;/code&gt; call which fits that output port we defined with a listener, in this case a naive one that just prints everything it gets to the console.&lt;/p&gt;

&lt;p&gt;This is awesome.&lt;/p&gt;

&lt;p&gt;It&#39;s awesome enough that I&#39;m seriously considering Elm for some production work &lt;i&gt;at&lt;/i&gt; work. Because I want to apply Elm in the places where it&#39;ll do massive amounts of good, and leave the other stuff to stateful JavaScript programs. Using the ports approach above, I can get exactly that. If there was something similar for Hskell, I&#39;d probably have taken the plunge and built something with it by now&lt;a href=&quot;#foot-Mon-Feb-17-150312EST-2014&quot; name=&quot;note-Mon-Feb-17-150312EST-2014&quot;&gt;[8]&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;In Case You&#39;re Reading, &lt;a href=&quot;https://github.com/evancz&quot;&gt;evancz&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;There are still a few minor headaches with the language, though thankfully I didn&#39;t have to stub my toe on most of them this time around. The only ones that ended up being annoying, or will be very shortly are&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;No signal defaults from within &lt;code&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;.elm&lt;/span&gt;&lt;/code&gt; files&lt;/b&gt;. This bites during development. When you have an Elm module that will depend on an outside signal for its operation, you have to set a default value for that signal outside. This is ok once you&#39;ve got the embedding file together, but it does mean that that second &lt;code&gt;Autocomplete.elm&lt;/code&gt; file above will give you the error 

&lt;pre&gt;Initialization Error: port &#39;wordList&#39; was not given an input!
    Open the developer console for more details.&lt;/pre&gt;

if you try to run it standalone without modifications. The workaround I&#39;ve been using is to comment out the &lt;code&gt;port&lt;/code&gt; declaration line, and add one that reads &lt;code&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;wordList&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; constant [&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;one&quot;&lt;/span&gt;, &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;two&quot;&lt;/span&gt;, &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;three&quot;&lt;/span&gt;, &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;four&quot;&lt;/span&gt;, &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;five&quot;&lt;/span&gt;, &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;six&quot;&lt;/span&gt;]&lt;/code&gt;. It works, but I&#39;d rather not have to do it.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;No Haskell-style sections&lt;/b&gt;. It only bit once in this program, and it&#39;s tolerable, but I&#39;d much rather write &lt;code&gt;(&lt;span style=&quot;color: #a0522d;&quot;&gt;/=&lt;/span&gt;&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;&quot;&lt;/span&gt;)&lt;/code&gt; than the equivalent, but syntactically noisier &lt;code&gt;(&lt;span style=&quot;color: #a0522d;&quot;&gt;\&lt;/span&gt;s &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; s &lt;span style=&quot;color: #a0522d;&quot;&gt;/=&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;&quot;&lt;/span&gt;)&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;No Indexing&lt;/b&gt;. I&#39;m almost convinced this has to be an omission on my part, and there&#39;s actually a way to do it out of the box, because it seems mildly bizarre to have &lt;a href=&quot;http://library.elm-lang.org/catalog/evancz-Elm/0.11/List&quot;&gt;&lt;code&gt;List.head&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;http://library.elm-lang.org/catalog/evancz-Elm/0.11/String&quot;&gt;&lt;code&gt;String.sub&lt;/code&gt;&lt;/a&gt; in a language, but no list indexing operator or function. If there is one, just point me to it. In the meantime, you can define your own minimal version as &lt;code&gt;(&lt;span style=&quot;color: #0000ff;&quot;&gt;!!&lt;/span&gt;) lst ix &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; lst &lt;span style=&quot;color: #a0522d;&quot;&gt;|&amp;gt;&lt;/span&gt; drop ix &lt;span style=&quot;color: #a0522d;&quot;&gt;|&amp;gt;&lt;/span&gt; head&lt;/code&gt;, or maybe 

&lt;pre&gt;(&lt;span style=&quot;color: #0000ff;&quot;&gt;!!&lt;/span&gt;) lst ix &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;case&lt;/span&gt; drop ix lst &lt;span style=&quot;color: #a020f0;&quot;&gt;of&lt;/span&gt;
                &lt;span style=&quot;color: #228b22;&quot;&gt;[]&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Nothing&lt;/span&gt;
                sub &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Just&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;|&lt;/span&gt; head sub&lt;/pre&gt;

 if getting out of array bounds gives you pause. Neither of these deals with negative indices, but they&#39;ll give you trivial indexing capabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That&#39;s that, I guess. I &lt;i&gt;was&lt;/i&gt; going to talk a bit about &lt;a href=&quot;http://purelang.bitbucket.org/&quot;&gt;Pure&lt;/a&gt;. And &lt;a href=&quot;http://en.wikipedia.org/wiki/Forth_%28programming_language%29&quot;&gt;Forth&lt;/a&gt;. And maybe incidentally a bit about &lt;a href=&quot;http://gcc.gnu.org/c99status.html&quot;&gt;C&lt;/a&gt;, but this is way longer than I was expecting already, so I think I&#39;ll call it for today.&lt;/p&gt;

&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Mon-Feb-17-150009EST-2014&quot; name=&quot;foot-Mon-Feb-17-150009EST-2014&quot;&gt;[back]&lt;/a&gt; - Admittedly this took something like hours total. Writing it involved a lot of experimentation and documentation browsing, and I did a quick clean-up pass afterwards. I&#39;m really hoping the development time goes down as I get more practice with the language and type system.&lt;/p&gt;

&lt;p&gt;2 - &lt;a href=&quot;#note-Mon-Feb-17-150016EST-2014&quot; name=&quot;foot-Mon-Feb-17-150016EST-2014&quot;&gt;[back]&lt;/a&gt; - Actually hang on. If you&#39;re new to the FRP thing, I should clarify that you never &lt;i&gt;really&lt;/i&gt; change things. Remember; any stateful component is represented as the lazy, infinite list of its complete history. What I really meant by the shorthand &quot;change it&quot; is &quot;merge multiple signals of the same type in a way that gives one of them primacy in certain situations&quot;. It&#39;s counter-intuitive the first few times, but it&#39;s helpful to keep the perspective in mind when you&#39;re dealing with Elms.&lt;/p&gt;

&lt;p&gt;3 - &lt;a href=&quot;#note-Mon-Feb-17-150022EST-2014&quot; name=&quot;foot-Mon-Feb-17-150022EST-2014&quot;&gt;[back]&lt;/a&gt; - And hence will change on a &lt;code&gt;keyDown&lt;/code&gt; or &lt;code&gt;keyUp&lt;/code&gt; event for that key.&lt;/p&gt;

&lt;p&gt;4 - &lt;a href=&quot;#note-Mon-Feb-17-150025EST-2014&quot; name=&quot;foot-Mon-Feb-17-150025EST-2014&quot;&gt;[back]&lt;/a&gt; - And will therefore change on either ctrl/space &lt;code&gt;keyDown&lt;/code&gt;, whichever is second and on ctrl/space &lt;code&gt;keyUp&lt;/code&gt;, whichever is first.&lt;/p&gt;

&lt;p&gt;5 - &lt;a href=&quot;#note-Mon-Feb-17-150223EST-2014&quot; name=&quot;foot-Mon-Feb-17-150223EST-2014&quot;&gt;[back]&lt;/a&gt; - It&#39;s &lt;code&gt;dropRepeats &lt;span style=&quot;color: #0000ff;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Signal&lt;/span&gt; a &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Signal&lt;/span&gt; a&lt;/code&gt;, in case you really, &lt;i&gt;really&lt;/i&gt; care.&lt;/p&gt;

&lt;p&gt;6 - &lt;a href=&quot;#note-Mon-Feb-17-150245EST-2014&quot; name=&quot;foot-Mon-Feb-17-150245EST-2014&quot;&gt;[back]&lt;/a&gt; - That&#39;s the &lt;code&gt;(merge Keyboard.enter esc)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;7 - &lt;a href=&quot;#note-Mon-Feb-17-150258EST-2014&quot; name=&quot;foot-Mon-Feb-17-150258EST-2014&quot;&gt;[back]&lt;/a&gt; - Assuming those were accurate urls for &lt;code&gt;elm-runtime.js&lt;/code&gt; and &lt;code&gt;Autocomplete.js&lt;/code&gt; on your system.&lt;/p&gt;

&lt;p&gt;8 - &lt;a href=&quot;#note-Mon-Feb-17-150312EST-2014&quot; name=&quot;foot-Mon-Feb-17-150312EST-2014&quot;&gt;[back]&lt;/a&gt; - For the record, there &lt;i&gt;might&lt;/i&gt; be something like it for Haskell, you&#39;ll hear excited giggling from me if I happen to find it. For the moment, I&#39;m still evaluating &lt;a href=&quot;http://www.haskell.org/haskellwiki/Functional_Reactive_Programming&quot;&gt;the FRP section of the Hasekellwiki&lt;/a&gt;.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/982376221181944036/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2014/02/autocompletion-example-in-elm.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/982376221181944036'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/982376221181944036'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2014/02/autocompletion-example-in-elm.html' title='Autocompletion Example with Ports in Elm'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-7925849450040541443</id><published>2014-02-09T00:14:00.000-08:00</published><updated>2014-02-09T00:14:31.017-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Common Lisp"/><category scheme="http://www.blogger.com/atom/ns#" term="Databases"/><category scheme="http://www.blogger.com/atom/ns#" term="Erlang"/><category scheme="http://www.blogger.com/atom/ns#" term="Idea Peeling"/><category scheme="http://www.blogger.com/atom/ns#" term="Speculation"/><title type='text'>Fact Bases and Total History</title><content type='html'>&lt;p&gt;No, since you ask, I haven&#39;t read anything related to &lt;a href=&quot;http://www.datomic.com/&quot;&gt;datomic&lt;/a&gt;, though &lt;a href=&quot;https://github.com/CompSciCabal&quot;&gt;friends&lt;/a&gt; keep telling me I &lt;i&gt;should&lt;/i&gt;. This is just stuff we&#39;ve been talking about at the &lt;a href=&quot;https://github.com/CompSciCabal/SMRTYPRTY/tree/master/sicp&quot;&gt;Toronto SICP reading group&lt;/a&gt;, and a couple of other places.&lt;/p&gt;

&lt;p&gt;The context was mildly different; we had this conversation in relation to the notional bank accounts from &lt;a href=&quot;http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-19.html#%_chap_3&quot;&gt;chapter 3 of SICP&lt;/a&gt; where they introduce mutable state. The discussed version would have been simpler to optimize and manipulate, since it was entirely numeric, but I&#39;ve &lt;i&gt;also&lt;/i&gt; got &lt;a href=&quot;https://en.wikipedia.org/wiki/Triplestore&quot;&gt;fact-bases&lt;/a&gt; on my mind thanks to a &lt;a href=&quot;https://github.com/guitarvydas&quot;&gt;now co-worker&lt;/a&gt; who&#39;s thought pretty deeply about them.&lt;/p&gt;

&lt;p&gt;The conversation touched on total-history data-structures, and their effects on performance and convenience. The end result is &lt;a href=&quot;https://github.com/Inaimathi/fact-base&quot;&gt;this little project&lt;/a&gt; I just put together over the course of half an afternoon.&lt;/p&gt;

&lt;h3&gt;Let me back up...&lt;/h3&gt;

&lt;p&gt;Imagine a toy bank account.&lt;/p&gt;

&lt;p&gt;The basic one proposed in the book is as simple as a balance, a &lt;code&gt;get&lt;/code&gt;ter, and a pair of setters named &lt;code&gt;deposit&lt;/code&gt; and &lt;code&gt;withdraw&lt;/code&gt;. You could add more detail, like interest rates and appropriate calculation functions, authentication mechanisms, and a designated owners list, but that&#39;s all beside the point.&lt;/p&gt;

&lt;p&gt;Regardless of how much detail you imagined, you probably think about the principal structure being &lt;code&gt;the current balance&lt;/code&gt;, hence simple numeric value of some precision. A total-history bank account is not that; it&#39;s a starting state (lets say 0), as well as The Total History (hence the name) of all transactions or modifications affecting it. So, instead of something like&lt;/p&gt;

&lt;pre&gt;$50.34&lt;/pre&gt;

&lt;p&gt;you&#39;re looking at a thing more like&lt;/p&gt;

&lt;pre&gt;&#39;(...
  (3600901270 &lt;span style=&quot;color: #483d8b;&quot;&gt;:deposit&lt;/span&gt; +100)
  (3600913394 &lt;span style=&quot;color: #483d8b;&quot;&gt;:withdraw&lt;/span&gt; -20)
  (3600913519 &lt;span style=&quot;color: #483d8b;&quot;&gt;:purchase&lt;/span&gt; -29.66))&lt;/pre&gt;

&lt;p&gt;stretching back from the beginning of the accounts&#39; existence to &lt;code&gt;now&lt;/code&gt;. This means that you have access to the &quot;current value&quot; of the account at any given time in its history. You can go back and check what happened and when, and if you like, you can ask questions like &quot;What would it look like today if I had made an extra deposit here, and an extra withdrawal here?&quot; In order to get the current value, you &lt;i&gt;have&lt;/i&gt; to project it. That is, you need to go back through history and apply all the recorded events in order to see what falls out the other end. If you really are doing basic numeric modifications, it&#39;s pretty easy to parallelize some parts of that projection process, but I&#39;ll leave that as a thought experiment for the reader.&lt;/p&gt;

&lt;p&gt;Bank accounts aren&#39;t the only things you can model this way; specifically, fact-bases can be usefully thought of in this manner.&lt;/p&gt;

&lt;h3&gt;Now then...&lt;/h3&gt;

&lt;p&gt;It turns out that total-history structures give you some interesting properties and challenges.&lt;/p&gt;

&lt;p&gt;First, if you want &lt;i&gt;all&lt;/i&gt; of history, you can never delete anything. You have to put in deletion tokens which remove some element or class of elements from your corpus. &lt;i&gt;Because&lt;/i&gt; you can never delete anything, a total-history data-structure has the nice property of being append-only. Which means that you can play some neat optimization tricks in serializing it to disk, like say, clustering deltas. This comes in really handy for very large data sets, or ones which are updated very frequently. Since you&#39;re only dealing with shipping diffs around, you can easily save yourself bandwidth on keeping copies in sync, or you could easily break your corpus up across different physical drives. Undo/redo also becomes fairly simple to layer on top of a corpus that already uses this approach.&lt;/p&gt;

&lt;p&gt;Second, time-stamping becomes pretty critical. If you took a look at &lt;a href=&quot;https://github.com/Inaimathi/fact-base&quot;&gt;that github link above&lt;/a&gt;, and poked around in &lt;a href=&quot;https://github.com/Inaimathi/fact-base/blob/master/fact-base.lisp&quot;&gt;here&lt;/a&gt;, you&#39;ll have noticed that I&#39;m using &lt;a href=&quot;http://common-lisp.net/project/local-time/&quot;&gt;&lt;code&gt;local-time&lt;/code&gt;&lt;/a&gt; rather than &lt;a href=&quot;http://www.lispworks.com/documentation/HyperSpec/Body/f_get_un.htm&quot;&gt;&lt;code&gt;get-universal-time&lt;/code&gt;&lt;/a&gt; because I need much finer granularity than seconds. Going to microseconds doesn&#39;t fully solve the problem, of course; if your throughput is high enough, there might still be collisions, and therefore potential data loss/duplication on updates. Putting something scalable together in Erlang would be easier, because &lt;a href=&quot;http://www.erlang.org/doc/man/erlang.html#now-0&quot;&gt;&lt;code&gt;now/0&lt;/code&gt;&lt;/a&gt; &lt;i&gt;guarantees&lt;/i&gt; unique values on subsequent invocations.&lt;/p&gt;

&lt;p&gt;Still open decisions are how to go about storing deletion tokens, and when/how aggressively to prune history. A passable answer for the second is &quot;never&quot;, so that&#39;s what I&#39;m going with for the moment. The first one doesn&#39;t seem to have a right answer.&lt;/p&gt;

&lt;h3&gt;Storing deletion tokens...&lt;/h3&gt;

&lt;p&gt;The three approaches I can see off the top of my head are storing a deletion index, storing a deletion value, and storing a deletion template. I&#39;m doing the third at the moment, though I&#39;m not convinced it&#39;s the right approach. So lets start with that.&lt;/p&gt;

&lt;b&gt;Deletion Template&lt;/b&gt;

&lt;p&gt;Basically the deletion primitive looks like &lt;code&gt;(delete! (list _ :subject _) fact-base)&lt;/code&gt;, which goes through and deletes any fact whose second element is &lt;code&gt;:subject&lt;/code&gt;, and also keeps that matching template as an indicator. A deletion entry then looks like&lt;/p&gt;

&lt;pre&gt;(&amp;lt;timestamp&amp;gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:delete&lt;/span&gt; (list _ &lt;span style=&quot;color: #483d8b;&quot;&gt;:subject&lt;/span&gt; _))&lt;/pre&gt;

&lt;p&gt;When you go to apply this particular deletion token, you&#39;ll need to create the function that checks for a match against it, then run that function across your built up state, removing anything it marks. There are three downsides here. First, this deletion token might pick up things other than the specific facts that it actually deletes in any particular traversal, which means that prospective evaluation gets more complicated. Second, because it&#39;s ambiguous, you can&#39;t easily reverse it; if you&#39;re building up state, you can&#39;t just back up over a deletion token, you need to throw away your accumulated state and start from the beginning again to get to the point you were at before applying it. Third, because it involves keeping a piece of match logic in the record, this approach means pulling out &lt;code&gt;eval&lt;/code&gt; during de-serialization.&lt;/p&gt;

&lt;p&gt;On the flip-side, it&#39;s easily parallelizable, and it doesn&#39;t care one whit about the order of the facts its traversing or the direction of traversal.&lt;/p&gt;

&lt;b&gt;Deletion Index&lt;/b&gt;

&lt;p&gt;This approach just has you keep the offset of the removed fact. A deletion token looks like&lt;/p&gt;

&lt;pre&gt;(&amp;lt;timestamp&amp;gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:delete&lt;/span&gt; 37)&lt;/pre&gt;

&lt;p&gt;or maybe &lt;/p&gt;

&lt;pre&gt;(&amp;lt;timestamp&amp;gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:delete&lt;/span&gt; (list 13 572 1335))&lt;/pre&gt;

&lt;p&gt;To apply this one, you go back through your built-up state and drop the &lt;code&gt;nth&lt;/code&gt; elements. Mostly the same downsides as the &lt;b&gt;Deletion Template&lt;/b&gt;; it gets a bit tricky when you want prospective change projection and it isn&#39;t cleanly reversible. It&#39;s mildly easier on memory, since we&#39;re just slinging integers around, and it doesn&#39;t need &lt;code&gt;eval&lt;/code&gt;, but it suddenly matters which direction you&#39;re traversing your corpus in, it matters how your corpus is ordered, and I could see it getting in the way of parallelization later.&lt;/p&gt;

&lt;b&gt;Deletion Value&lt;/b&gt;

&lt;p&gt;A deletion value token looks something like&lt;/p&gt;

&lt;pre&gt;(&amp;lt;timestamp&amp;gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:delete&lt;/span&gt; (&amp;lt;id&amp;gt; &lt;span style=&quot;color: #483d8b;&quot;&gt;:subject&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;whatever the third value is&quot;&lt;/span&gt;))&lt;/pre&gt;

&lt;p&gt;You apply this by going through the accumulated corpus and removing the first fact that matches it. Granted, it&#39;s slower in general (because applying it in general involves an arbitrary tree-compare), and it&#39;s more wasteful of disk space (because we have to store those arbitrary trees as well as comparing them with facts to remove). But. Depending on how strictly you enforce it, this one is more easily reversible, and it doesn&#39;t need &lt;code&gt;eval&lt;/code&gt; either, since it&#39;s just storing a value.&lt;/p&gt;

&lt;h3&gt;Wrapping up...&lt;/h3&gt;

&lt;p&gt;A couple of other thoughts I&#39;d like to leave percolating:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It might be possible to get the best of both worlds by making sure that a deletion token remembers the particular members it removed &lt;i&gt;at application time&lt;/i&gt;. That would let both the Template and Index approach reverse easily, though it would complicate the projection process somewhat.&lt;/li&gt;
  &lt;li&gt;It might be useful to have a layer of meta-tokens. That is, insertions in &lt;code&gt;history&lt;/code&gt; that modify other history entries. Off the top of my head, only &lt;code&gt;:ignore&lt;/code&gt; or &lt;code&gt;:duplicate&lt;/code&gt; seem like they&#39;d be significantly useful. On the plus side, you now have a meta layer to these histories which gives you more flexibility in using them. On the other hand, you now need to have one of efficient reversals, a two-pass loading procedure, or really &lt;i&gt;really&lt;/i&gt; shitty performance for heavily meta-tagged histories.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That&#39;s that. Not the most flowing narrative I&#39;ve ever produced, but I think it touched on one or two interesting ideas. And anyhow, I&#39;m still chewing over most of this. I&#39;ll let you know how it goes, and if I end up finding a real use for it.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/7925849450040541443/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2014/02/fact-bases-and-total-history.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/7925849450040541443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/7925849450040541443'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2014/02/fact-bases-and-total-history.html' title='Fact Bases and Total History'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-5603640565423012165</id><published>2014-01-28T19:39:00.000-08:00</published><updated>2014-01-28T19:40:07.046-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Idea Peeling"/><title type='text'>Update, and the Finer Points of Quasimodes</title><content type='html'>&lt;p&gt;I was going to say &quot;this&#39;ll just be a quick update&quot;, but on reflection, I&#39;m not sure that&#39;s true. I want to discuss two specific things I recently implemented, as well as what&#39;s been going on lately project-wise.&lt;/p&gt;

&lt;p&gt;First things first.&lt;/p&gt;

&lt;h3&gt;AOSA Chapter&lt;/h3&gt;

&lt;p&gt;I&#39;m doing a chapter for the upcoming book called &lt;i&gt;&lt;a href=&quot;https://github.com/aosabook/500lines&quot;&gt;500 Lines or Less&lt;/a&gt;&lt;/i&gt;. It&#39;s the fourth installment in the &lt;a href=&quot;http://aosabook.org/en/index.html&quot;&gt;Architecture of Open Source Applications series&lt;/a&gt;. To, I should hope, no ones&#39; surprise, I&#39;m doing a write-up of the &lt;a href=&quot;https://github.com/Inaimathi/house&quot;&gt;House&lt;/a&gt; asynchronous server currently serving as the back-end for the &lt;a href=&quot;https://github.com/Inaimathi/deal&quot;&gt;Deal&lt;/a&gt; project. I&#39;ve seen fit to simplify the server a bit for entry, since the real live one masses slightly more than 500 lines. You can see the result &lt;a href=&quot;https://github.com/Inaimathi/500lines/tree/master/async-web-server&quot;&gt;here&lt;/a&gt;; that&#39;s the House server with the session and static file mechanisms stripped out, which happens to weigh in at just over 400 lines of fairly readable Common Lisp. The first 1/2 draft of the prose write-up is &lt;a href=&quot;https://github.com/Inaimathi/500lines/blob/master/async-web-server/writeup.md&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This process is new to me. Granted, I write a fuck-ton, but I&#39;m usually also the editor and proofreader. Frankly, I don&#39;t envy anyone that job. It may not look like it, but I end up chopping a good half of my output before it gets posted anywhere, and then tweak about a third of the result after the fact. Hopefully, involving other eyes will mean a more refined exposition than I usually manage.&lt;/p&gt;

&lt;h3&gt;2dmacs&lt;/h3&gt;

&lt;p&gt;I&#39;m still working on that visual editor at work. Internally, we&#39;ve taken to calling the project &quot;&lt;code&gt;2dmacs&lt;/code&gt;&quot;, pronounced &quot;two-dee-macs&quot;. Hopefully, I can live up to the name. We&#39;re going to do some user trials tomorrow, just to see what the target audience of 5 thinks. It&#39;s still missing one or two big features, mostly history related and mostly pretty straight-forward to implement. But based on my own experience, it&#39;s already more productive than the alternatives for the sorts of things we&#39;ll be doing. I&#39;ll let you know how it goes.&lt;/p&gt;

&lt;p&gt;Now then, moving on to a couple of implementation details. Except that I still can&#39;t show you code. Sorry.&lt;/p&gt;

&lt;h3&gt;Quasimodes&lt;/h3&gt;

&lt;p&gt;Quasimodes are another thing I picked up from &lt;a href=&quot;http://www.amazon.com/The-Humane-Interface-Directions-Interactive/dp/0201379376&quot;&gt;that Raskin book&lt;/a&gt;&lt;a href=&quot;#foot-Tue-Jan-28-214701EST-2014&quot; name=&quot;note-Tue-Jan-28-214701EST-2014&quot;&gt;[1]&lt;/a&gt;. The idea is to let holding a particular key kick off a different interaction mode and cancel out of it on release. Raskin&#39;s example is of the &lt;code&gt;Caps Lock&lt;/code&gt; and &lt;code&gt;Shift&lt;/code&gt; keys. Basically, &lt;code&gt;Caps Lock&lt;/code&gt; switches the user into a mode where standard keyboard keys do something different, whereas &lt;code&gt;Shift&lt;/code&gt; activates a quasimode to the same ends. The argument is that the second is better because there&#39;s no confusion about what state the system is currently in. If you&#39;re holding shift, you&#39;re in shout mode. If you&#39;re not, you&#39;re not. Comparatively, as long as your keyboard has a Caps Lock key, you might be dumped into Shout mode by an accidental keypress. If you&#39;ve ever tried to type in a password, you know the problems this can cause. Quasimodes neatly sidestep the issue by keeping a mode active only as long as the user deliberately holds a particular key.&lt;/p&gt;

&lt;p&gt;Implementing this in Javascript turns out to be non-trivial. Even after you&#39;ve built up your own little event system around the various input actions a user can take. What you naively need to do is capture the &lt;code&gt;keydown&lt;/code&gt; event, activate a given quasimode&lt;a href=&quot;#foot-Tue-Jan-28-214704EST-2014&quot; name=&quot;note-Tue-Jan-28-214704EST-2014&quot;&gt;[2]&lt;/a&gt;, and clean up when you get a &lt;code&gt;keyup&lt;/code&gt; corresponding to the initiating &lt;code&gt;keydown&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That has some implications, though.&lt;/p&gt;

&lt;p&gt;First, it requires the ability to &lt;i&gt;optionally&lt;/i&gt; route events through particular functions. Which means that you have to have a layer of indirection between the default HTML event handlers and your systems&#39; commands. Luckily, the system I&#39;m building had that already for unrelated reasons, but if you&#39;re trying to do this properly in &lt;i&gt;your&lt;/i&gt; system, it might mean some architectural changes.&lt;/p&gt;

&lt;p&gt;Second, because we&#39;re dealing with browser events, we need to be able to cancel out of a quasimode with something other than the initiating keydown event&lt;a href=&quot;#foot-Tue-Jan-28-214707EST-2014&quot; name=&quot;note-Tue-Jan-28-214707EST-2014&quot;&gt;[3]&lt;/a&gt;. In my case, I had already wired &lt;code&gt;&amp;lt;&lt;span style=&quot;color: #0000ff;&quot;&gt;esc&lt;/span&gt;&amp;gt;&lt;/code&gt; as the generic cancel button. It already drops you out of half-completed keystrokes and resets some small pieces of internal state to their original positions. So it made perfect sense to just add &quot;exit any quasimodes&quot; to the list of things it does.&lt;/p&gt;

&lt;p&gt;Finally, unless you want to let quasimodes monopolize the keys they&#39;ll be bound to, it means having some logic involved that distinguishes between a regular keypress and a quasimode invocation. That ended up being resolved a touch hackily; if you press a quasimode key, but don&#39;t trip any of that modes&#39; internal bindings before releasing it, it gets interpreted as a vanilla keypress. Not sure that&#39;s the best approach long-term, but I can&#39;t think of a simpler one off the top of my head.&lt;/p&gt;

&lt;h3&gt;Selections&lt;/h3&gt;

&lt;p&gt;A particular type of quasimode that gave me some pause is area selection. It turns out this is more complicated than you&#39;d think at first glance. If you have a system that models various things as sets of points, and points as well as things are selectable and groupable, then there are a bunch of independent axes that you might be thinking about selections:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;additive/subtractive/replacing&lt;/b&gt; You might reasonably be looking to add to your existing selection, remove elements from it, or replace your existing selection with the set of elements you&#39;re about to specify by area.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;intersecting/containing&lt;/b&gt; You might want to select any thing whose bounding box &lt;i&gt;touches&lt;/i&gt; your selection, or you might want to limit yourself to objects that are entirely &lt;i&gt;contained&lt;/i&gt; inside said selection.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;element/point&lt;/b&gt; You might want to select things, or you might want to select the points that compose them.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;top-level/deep&lt;/b&gt; You might want to select the top-level groups of elements, or you might want to select the leaf nodes.&lt;/p&gt;

&lt;p&gt;The point here is that these are all axes on which the user might choose independently, and most of them are reasonable choices. However, you don&#39;t want to have 24 different quasimodes, or even one quasimode with 23 different modifier keys to accomodate them all. After giving it some thought, I made the drag-select interaction default to an &lt;b&gt;additive, intersecting, element, top-level&lt;/b&gt; selection. My intuition is that &lt;b&gt;point&lt;/b&gt; and &lt;b&gt;subtractive&lt;/b&gt; selections are going to be rare and simple enough that we won&#39;t need area support for them, that &lt;b&gt;replacing&lt;/b&gt; selections are easy enough to counterfeit by hitting the &lt;code&gt;clear-selection&lt;/code&gt; keystroke before making a selection, and that I can add modifier keys to distinguish between &lt;b&gt;intersecting/containing&lt;/b&gt; and &lt;b&gt;top-level/deep&lt;/b&gt; if needed. I&#39;ll let you know how that goes too.&lt;/p&gt;

&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Tue-Jan-28-214701EST-2014&quot; name=&quot;foot-Tue-Jan-28-214701EST-2014&quot;&gt;[back]&lt;/a&gt; - Which I thoroughly recommend for anyone involved in interface design of any kind. I&#39;m kind of surprised they never made me read it in college, alongside &lt;a href=&quot;http://www.amazon.com/The-Design-Everyday-Things-Expanded/dp/0465050654&quot;&gt;Design of Everyday Things&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;2 - &lt;a href=&quot;#note-Tue-Jan-28-214704EST-2014&quot; name=&quot;foot-Tue-Jan-28-214704EST-2014&quot;&gt;[back]&lt;/a&gt; - Which means running its bindings instead of the global ones for the duration.&lt;/p&gt;

&lt;p&gt;3 - &lt;a href=&quot;#note-Tue-Jan-28-214707EST-2014&quot; name=&quot;foot-Tue-Jan-28-214707EST-2014&quot;&gt;[back]&lt;/a&gt; - An alert, or forced focus switch might take the user away from our window before we get the intended key released.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/5603640565423012165/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2014/01/update-and-finer-points-of-quasimodes.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/5603640565423012165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/5603640565423012165'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2014/01/update-and-finer-points-of-quasimodes.html' title='Update, and the Finer Points of Quasimodes'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-3244127532786078838</id><published>2014-01-24T08:28:00.003-08:00</published><updated>2014-03-08T15:24:18.991-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Clojure"/><category scheme="http://www.blogger.com/atom/ns#" term="Common Lisp"/><category scheme="http://www.blogger.com/atom/ns#" term="Lisp"/><category scheme="http://www.blogger.com/atom/ns#" term="Scheme"/><title type='text'>Which Lisp Should I Learn?</title><content type='html'>&lt;p&gt;I don&#39;t know why this keeps coming up lately, but it does. So, here we go:&lt;/p&gt;

&lt;h3&gt;My Recommendation&lt;/h3&gt;

&lt;p&gt;If you want to learn your first Lisp and already know something about the JVM&lt;a href=&quot;#foot-Fri-Jan-24-105200EST-2014&quot; name=&quot;note-Fri-Jan-24-105200EST-2014&quot;&gt;[1]&lt;/a&gt;, you should learn &lt;a href=&quot;http://clojure.org/&quot;&gt;Clojure&lt;/a&gt;&lt;a href=&quot;#foot-Fri-Jan-24-105205EST-2014&quot; name=&quot;note-Fri-Jan-24-105205EST-2014&quot;&gt;[2]&lt;/a&gt;. Otherwise, you should learn Scheme. Specifically, I recommend going the route that takes you through &lt;a href=&quot;http://racket-lang.org/&quot;&gt;Racket&lt;/a&gt;&lt;a href=&quot;#foot-Fri-Jan-24-105208EST-2014&quot; name=&quot;note-Fri-Jan-24-105208EST-2014&quot;&gt;[3]&lt;/a&gt;, and possibly through &lt;a href=&quot;https://github.com/sarabander/sicp-pdf/raw/master/sicp.pdf&quot;&gt;SICP&lt;/a&gt; or &lt;a href=&quot;http://htdp.org/&quot;&gt;HTDP&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you absolutely, positively must, I guess go ahead and learn Common Lisp.&lt;/p&gt;

&lt;h3&gt;Why&lt;/h3&gt;

&lt;p&gt;Clojure the language, as opposed to the current, main, half-fused-with-JVM implementation, is cleaner and more consistent than Common Lisp, which should help you learn it more easily. I&#39;ve gotten back talk about how there are lots more noobs learning Clojure, and as a result their libraries are in some disarray, and about the fact that the JVM is a sack of donkey balls you have to bite into every time you hit some sort of error&lt;a href=&quot;#foot-Fri-Jan-24-105212EST-2014&quot; name=&quot;note-Fri-Jan-24-105212EST-2014&quot;&gt;[4]&lt;/a&gt;, and about the general Clojure community pre-disposition to fashion trends. All of which may or may not be true, but I&#39;m specifically talking about &lt;i&gt;the language&lt;/i&gt;, not its ecosystem or stalwarts. Now granted, all of Racket, Clojure and Common Lisp&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;are built out of s-expressions&lt;/li&gt;
  &lt;li&gt;have &lt;code&gt;defmacro&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;so depending on how much work you&#39;re willing to put in, you can do whatever the fuck you want in all of them&lt;a href=&quot;#foot-Fri-Jan-24-105237EST-2014&quot; name=&quot;note-Fri-Jan-24-105237EST-2014&quot;&gt;[5]&lt;/a&gt;. However, in addition to knowing about prefix notation, and macros, and general Lisp program structure, here&#39;s an incomplete list of idiosyncrasies of Common Lisp that you have to commit to memory before you can be effective in it:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Functions and variables are in different namespaces, and each has constructs that deal with them explicitly. You need to use &lt;code&gt;defvar&lt;/code&gt;/&lt;code&gt;defun&lt;/code&gt; and &lt;code&gt;let&lt;/code&gt;/&lt;code&gt;flet&lt;/code&gt; depending on whether you&#39;re using functions or variables. If you&#39;re passing symbol names around, symbols that denote variables can be sent around as &lt;code&gt;&#39;foo&lt;/code&gt; whereas symbols that denote functions should be sent around as &lt;code&gt;#&#39;foo&lt;/code&gt;. If you&#39;re trying to pass a function around in the variable &lt;code&gt;foo&lt;/code&gt;, you need to &lt;code&gt;(funcall foo arg)&lt;/code&gt; or possibly &lt;code&gt;(apply foo args)&lt;/code&gt;, rather than just &lt;code&gt;(foo arg)&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Most functions that deal with lists are functional, except the standard &lt;code&gt;sort&lt;/code&gt; and the default &lt;code&gt;mapcan&lt;/code&gt;, both of which destructively modify the list you pass them.&lt;/li&gt;
  &lt;li&gt;You can define methods for your classes, but can&#39;t easily use certain default names that are bound to top-level functions. Such as &lt;code&gt;length&lt;/code&gt;, or the arithmetic primitives. Which is why you frequently see methods like &lt;code&gt;duration-add&lt;/code&gt; or &lt;code&gt;matrix-mult&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;There are 7 commonly used equality operators, &lt;code&gt;eq&lt;/code&gt;, &lt;code&gt;eql&lt;/code&gt;, &lt;code&gt;equal&lt;/code&gt;, &lt;code&gt;equalp&lt;/code&gt;, &lt;code&gt;string=&lt;/code&gt;, &lt;code&gt;char=&lt;/code&gt; and &lt;code&gt;=&lt;/code&gt;&lt;a href=&quot;#foot-Fri-Jan-24-105253EST-2014&quot; name=&quot;note-Fri-Jan-24-105253EST-2014&quot;&gt;[6]&lt;/a&gt;, each of which has mildly different, sometimes implementation-specific, behavior. Granted, because CL isn&#39;t a pure language, you need at least 2 of those, but 7 is still a bit much to have people memorize.&lt;/li&gt;
  &lt;li&gt;There are three different local binding mechanisms that you must decide between depending on whether you want to be able to refer to earlier symbols in the same binding set, or whether you want symbols to be able to refer to themselves. You use &lt;code&gt;let&lt;/code&gt;/&lt;code&gt;flet&lt;/code&gt; if you don&#39;t care, &lt;code&gt;let*&lt;/code&gt; for variables where you want later bindings to be able to refer to earlier ones, and &lt;code&gt;labels&lt;/code&gt; for functions where you want bindings to be able to refer to themselves or earlier bindings.&lt;/li&gt;
  &lt;li&gt;There are many, &lt;i&gt;many&lt;/i&gt; implementations of Common Lisp. The popular ones at the moment are &lt;a href=&quot;http://www.sbcl.org/&quot;&gt;SBCL&lt;/a&gt; and &lt;a href=&quot;http://ccl.clozure.com/download.html&quot;&gt;CCL&lt;/a&gt;, but I&#39;ve personally seen &lt;a href=&quot;http://www.clisp.org/&quot;&gt;CLISP&lt;/a&gt;, &lt;a href=&quot;http://ecls.sourceforge.net/&quot;&gt;ECL&lt;/a&gt; and &lt;a href=&quot;http://www.lispworks.com/products/lispworks.html&quot;&gt;Lispworks&lt;/a&gt; around too. More are available, and you might run into a lot of them in the wild. If you want to write portable code, you have to jump through some hoops. The implementation-specifics range from the finer points of equality operator behaviors, to the behavior of &lt;code&gt;handler-case&lt;/code&gt;&lt;a href=&quot;#foot-Fri-Jan-24-105327EST-2014&quot; name=&quot;note-Fri-Jan-24-105327EST-2014&quot;&gt;[7]&lt;/a&gt;, to the types you can specialize on with &lt;code&gt;defmethod&lt;/code&gt;, to the presence and behavior of threads, to the contexts in which you can pass streams around, to the names of various extension functions. For a small but representative example, take a look at &lt;a href=&quot;https://github.com/Inaimathi/cl-git-fs/blob/master/util.lisp#L12-L56&quot;&gt;what it takes to temporarily change your current directory in an implementation-independent way&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Indexing into different constructs takes different forms. You need &lt;code&gt;nth&lt;/code&gt; for lists, &lt;code&gt;aref&lt;/code&gt; for arrays and vectors, &lt;code&gt;gethash&lt;/code&gt; for hashes and &lt;code&gt;slot-value&lt;/code&gt; for CLOS instances&lt;a href=&quot;#foot-Fri-Jan-24-105330EST-2014&quot; name=&quot;note-Fri-Jan-24-105330EST-2014&quot;&gt;[8]&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;You can&#39;t use the symbol &lt;code&gt;t&lt;/code&gt; anywhere. No, not even local scopes. If you try, you&#39;ll get warnings or errors&lt;a href=&quot;#foot-Fri-Jan-24-105333EST-2014&quot; name=&quot;note-Fri-Jan-24-105333EST-2014&quot;&gt;[9]&lt;/a&gt;, because &lt;code&gt;t&lt;/code&gt; is the top-level designated Truth symbol, even though anything other than &lt;code&gt;NIL&lt;/code&gt; &lt;a href=&quot;http://langnostic.blogspot.ca/2013/05/truthy-and-falsy-vs-explicit.html&quot;&gt;evaluates truthily&lt;/a&gt; in a boolean context.&lt;/li&gt;
  &lt;li&gt;A hash isn&#39;t a list, and a CLOS instance isn&#39;t anything like either. One way you&#39;d &lt;i&gt;like&lt;/i&gt; them to be similar is when you&#39;re traversing them. It seems fairly reasonable to expect &lt;code&gt;map&lt;/code&gt;-likes to operate on hashes by treating them as a sequence of key/value pairs, and instances by treating their bound slots as key/value pairs. This is not how things work. If you want to map over instances that way, you need to do something like &lt;a href=&quot;https://github.com/Inaimathi/cl-mop/blob/master/package.lisp&quot;&gt;this&lt;/a&gt; and &lt;a href=&quot;https://github.com/Inaimathi/cl-mop/blob/master/cl-mop.lisp#L6-L21&quot;&gt;this&lt;/a&gt;. If you want to &lt;code&gt;map&lt;/code&gt; over hashes, you either use the hilariously mis-named &lt;code&gt;maphash&lt;/code&gt;&lt;a href=&quot;#foot-Fri-Jan-24-105336EST-2014&quot; name=&quot;note-Fri-Jan-24-105336EST-2014&quot;&gt;[10]&lt;/a&gt; or some idiosyncratic piece of the &lt;a href=&quot;http://www.gigamonkeys.com/book/loop-for-black-belts.html&quot;&gt;&lt;code&gt;loop&lt;/code&gt; DSL&lt;/a&gt; that lets you iterate over hash keys and hash values.&lt;/li&gt;
  &lt;li&gt;Common Lisp is case-insensitive. It takes whatever symbol input from you and upcases it internally. So &lt;code&gt;foo-bar&lt;/code&gt; and &lt;code&gt;foo-Bar&lt;/code&gt; both become &lt;code&gt;FOO-BAR&lt;/code&gt; behind the scenes. This is usually not a huge problem, unless you try to interoperate cleanly with newer data standards like CSS or JSON. That leaves you fumbling with &lt;code&gt;string&lt;/code&gt;s in situations where &lt;code&gt;symbol&lt;/code&gt;s and/or &lt;code&gt;keyword&lt;/code&gt;s really ought to do.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Like I said, this is a small sample. Just the stuff I thought of off the top of my head. I&#39;m sure I could come up with more if I put a day or two into it. And I&#39;m far from the most experienced Lisper out there, others would have more finer points for you, I&#39;m sure. But that&#39;s half the problem with little issues like this; experienced Lispers completely forget about them. It&#39;s the newbs that have trouble cramming these things into their heads.&lt;/p&gt;

&lt;p&gt;When I take a good look at that list, and then imagine the situations that led to each element, it&#39;s difficult to conclude that a wrong decision was made at any given point in time. Unfortunately, the sum of all of those potentially correct decisions is a giant system, the inherent rules of which look inconsistent if not outright hostile to human minds.&lt;/p&gt;

&lt;p&gt;I don&#39;t know if Clojure solves all of them.&lt;/p&gt;

&lt;p&gt;I&#39;ve done very little work with it, for reasons entirely unrelated to the language. For all I know, when you get deep enough into it, you get to inconsistencies and/or restrictions which are worse than anything I&#39;ve pointed out or could.&lt;/p&gt;

&lt;p&gt;But do me a favor, if you&#39;re a CL user, either hop over to this &lt;a href=&quot;http://tryclj.com/&quot;&gt;web REPL&lt;/a&gt;, or install &lt;code&gt;leiningen&lt;/code&gt; then hop into your local &lt;code&gt;lein repl&lt;/code&gt; and type along here:&lt;/p&gt;

&lt;pre&gt;user=&amp;gt; (&lt;span style=&quot;color: #a020f0;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;thing&lt;/span&gt; [8 7 6 5 4 3 2 1])
#&#39;user/thing
user=&amp;gt; (thing 0)
8
user=&amp;gt; (thing 3)
5
user=&amp;gt;(&lt;span style=&quot;color: #483d8b;&quot;&gt;map&lt;/span&gt; (&lt;span style=&quot;color: #a020f0;&quot;&gt;fn&lt;/span&gt; [n] (&lt;span style=&quot;color: #483d8b;&quot;&gt;+&lt;/span&gt; 3 n)) thing)
(11 10 9 8 7 6 5 4)
user=&amp;gt; (&lt;span style=&quot;color: #a020f0;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;thing&lt;/span&gt; {&lt;span style=&quot;color: #008b8b;&quot;&gt;:a&lt;/span&gt; 1 &lt;span style=&quot;color: #008b8b;&quot;&gt;:b&lt;/span&gt; 2 &lt;span style=&quot;color: #008b8b;&quot;&gt;:c&lt;/span&gt; 3})
#&#39;user/thing
user=&amp;gt; (thing &lt;span style=&quot;color: #008b8b;&quot;&gt;:c&lt;/span&gt;)
3
user=&amp;gt; (thing &lt;span style=&quot;color: #008b8b;&quot;&gt;:d&lt;/span&gt; 6)
6
user=&amp;gt; (thing &lt;span style=&quot;color: #008b8b;&quot;&gt;:a&lt;/span&gt; 6)
1
user=&amp;gt; (&lt;span style=&quot;color: #483d8b;&quot;&gt;map&lt;/span&gt; (&lt;span style=&quot;color: #a020f0;&quot;&gt;fn&lt;/span&gt; [[k v]] (&lt;span style=&quot;color: #483d8b;&quot;&gt;+&lt;/span&gt; v 2)) thing)
(3 4 5)
user=&amp;gt; (&lt;span style=&quot;color: #a020f0;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;thing&lt;/span&gt; #{1 2 3 4 5}) &lt;span style=&quot;color: #b22222;&quot;&gt;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;a set, in case you were wondering
&lt;/span&gt;#&#39;user/thing
user=&amp;gt; (thing 3)
3
user=&amp;gt; (thing 0) 
nil
user=&amp;gt; (&lt;span style=&quot;color: #483d8b;&quot;&gt;map&lt;/span&gt; (&lt;span style=&quot;color: #a020f0;&quot;&gt;fn&lt;/span&gt; [a] (&lt;span style=&quot;color: #483d8b;&quot;&gt;+&lt;/span&gt; a 2)) thing)
(3 4 5 6 7)
user=&amp;gt; (&lt;span style=&quot;color: #a020f0;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;triple&lt;/span&gt; (&lt;span style=&quot;color: #a020f0;&quot;&gt;fn&lt;/span&gt; [a] (&lt;span style=&quot;color: #483d8b;&quot;&gt;*&lt;/span&gt; a 3)))
#&#39;user/triple
user=&amp;gt; (triple 4)
12
user=&amp;gt; (&lt;span style=&quot;color: #483d8b;&quot;&gt;map&lt;/span&gt; triple thing)
(3 6 9 12 15)
user=&amp;gt; (&lt;span style=&quot;color: #483d8b;&quot;&gt;map&lt;/span&gt; (&lt;span style=&quot;color: #a020f0;&quot;&gt;fn&lt;/span&gt; [a] (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; [t (&lt;span style=&quot;color: #483d8b;&quot;&gt;-&lt;/span&gt; (triple a) 5)] (&lt;span style=&quot;color: #483d8b;&quot;&gt;*&lt;/span&gt; 2 t))) thing)
(-4 2 8 14 20)&lt;/pre&gt;

&lt;p&gt;Now think about how you would go about explaining to a novice programmer that it has to be more complicated than that.&lt;/p&gt;

&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Fri-Jan-24-105200EST-2014&quot; name=&quot;foot-Fri-Jan-24-105200EST-2014&quot;&gt;[back]&lt;/a&gt; - And don&#39;t have a strong dislike for it, obviously.&lt;/p&gt;

&lt;p&gt;2 - &lt;a href=&quot;#note-Fri-Jan-24-105205EST-2014&quot; name=&quot;foot-Fri-Jan-24-105205EST-2014&quot;&gt;[back]&lt;/a&gt; - Install it through &lt;a href=&quot;https://github.com/technomancy/leiningen&quot;&gt;Leiningen&lt;/a&gt;, which is available in the &lt;a href=&quot;http://packages.debian.org/sid/leiningen&quot;&gt;Debian repos&lt;/a&gt; in stable and unstable.&lt;/p&gt;

&lt;p&gt;3 - &lt;a href=&quot;#note-Fri-Jan-24-105208EST-2014&quot; name=&quot;foot-Fri-Jan-24-105208EST-2014&quot;&gt;[back]&lt;/a&gt; - Yes, I&#39;m fully aware that the Racket guys are trying to push this &quot;We&#39;re totally not Scheme&quot; thing. They&#39;re close enough from an external perspective. Just don&#39;t tell Jay McCarthy I said so.&lt;/p&gt;

&lt;p&gt;4 - &lt;a href=&quot;#note-Fri-Jan-24-105212EST-2014&quot; name=&quot;foot-Fri-Jan-24-105212EST-2014&quot;&gt;[back]&lt;/a&gt; - Which is certainly true, but mildly preferable to the alternative as long as you&#39;re used to that sort of thing.&lt;/p&gt;

&lt;p&gt;5 - &lt;a href=&quot;#note-Fri-Jan-24-105237EST-2014&quot; name=&quot;foot-Fri-Jan-24-105237EST-2014&quot;&gt;[back]&lt;/a&gt; - Except that Clojure is apparently missing Reader macros, which I always thought were kind of half-assedly implemented in Common Lisp. For what I consider the full-ass version, take a look at &lt;a href=&quot;http://www.haskell.org/haskellwiki/Quasiquotation&quot;&gt;how Haskell does it&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;6 - &lt;a href=&quot;#note-Fri-Jan-24-105253EST-2014&quot; name=&quot;foot-Fri-Jan-24-105253EST-2014&quot;&gt;[back]&lt;/a&gt; - Plus how many ever &lt;code&gt;*-equal&lt;/code&gt; functions you define for your own classes.&lt;/p&gt;

&lt;p&gt;7 - &lt;a href=&quot;#note-Fri-Jan-24-105327EST-2014&quot; name=&quot;foot-Fri-Jan-24-105327EST-2014&quot;&gt;[back]&lt;/a&gt; - The Common Lisp answer to the problems that call for &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt; in other languages.&lt;/p&gt;

&lt;p&gt;8 - &lt;a href=&quot;#note-Fri-Jan-24-105330EST-2014&quot; name=&quot;foot-Fri-Jan-24-105330EST-2014&quot;&gt;[back]&lt;/a&gt; - For the last, you can also define your own selectors using &lt;code&gt;:reader&lt;/code&gt; or &lt;code&gt;:accessor&lt;/code&gt; declarations.&lt;/p&gt;

&lt;p&gt;9 - &lt;a href=&quot;#note-Fri-Jan-24-105333EST-2014&quot; name=&quot;foot-Fri-Jan-24-105333EST-2014&quot;&gt;[back]&lt;/a&gt; - Which specific warning or error depends on implementation.&lt;/p&gt;

&lt;p&gt;10 - &lt;a href=&quot;#note-Fri-Jan-24-105336EST-2014&quot; name=&quot;foot-Fri-Jan-24-105336EST-2014&quot;&gt;[back]&lt;/a&gt; - Because it&#39;s not very much like &lt;code&gt;map&lt;/code&gt;. It returns nil and works by side-effect. Meaning that if you expect a sequence from it, you&#39;ll need to construct it yourself.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/3244127532786078838/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2014/01/what-lisp-should-i-learn.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/3244127532786078838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/3244127532786078838'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2014/01/what-lisp-should-i-learn.html' title='Which Lisp Should I Learn?'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-1820640473604997502</id><published>2014-01-04T14:42:00.000-08:00</published><updated>2014-01-07T17:42:34.629-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Common Lisp"/><category scheme="http://www.blogger.com/atom/ns#" term="Elisp"/><category scheme="http://www.blogger.com/atom/ns#" term="Emacs"/><category scheme="http://www.blogger.com/atom/ns#" term="git"/><category scheme="http://www.blogger.com/atom/ns#" term="Hardware"/><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming Environment"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming Interfaces"/><title type='text'>Debian Testing, Pi and Git</title><content type='html'>&lt;p&gt;That was a vacation, I guess.&lt;/p&gt;

&lt;p&gt;It was suspiciously taxing, all in all. Time off from work hasn&#39;t been nearly as relaxing since we had a kid, but that&#39;s a digression. Over the past little while, I&#39;ve managed to finally make use the 120G solid state drive I picked up half a year ago, install various distros, and put together about one third of a utility to ease a project or two I&#39;m working on in my spare time.&lt;/p&gt;

&lt;h3&gt;New Drive&lt;/h3&gt;

&lt;p&gt;It&#39;s at once larger and smaller than the last one. On the one hand, thanks to its smaller physical profile, I can fit it into my laptop with no mods. On the other hand, &lt;code&gt;df -h&lt;/code&gt; says &lt;code&gt;106G&lt;/code&gt;&lt;a href=&quot;#foot-Sat-Jan-04-174331EST-2014&quot; name=&quot;note-Sat-Jan-04-174331EST-2014&quot;&gt;[1]&lt;/a&gt; instead of &lt;code&gt;~28G&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That&#39;s it, nothing else to see here.&lt;/p&gt;

&lt;h3&gt;Fresh Install&lt;/h3&gt;

&lt;p&gt;Since I was between drives anyhow, I took the opportunity to get the fresh version of &lt;a href=&quot;http://www.debian.org/devel/debian-installer/&quot;&gt;Debian&lt;/a&gt; up and running. That was worth it, by the by, if for no other reason than they&#39;ve apparently poured enough bucketfulls of time into the networking code that I can now reliably connect to my wifi access point even if I&#39;m not within two meters of it. They also seemed to lick a problem I kept running into wherein the shutdown process would hang the machine&lt;a href=&quot;#foot-Sat-Jan-04-174334EST-2014&quot; name=&quot;note-Sat-Jan-04-174334EST-2014&quot;&gt;[2]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There were a few changes in my install routine, which is still vaguely based on&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;## &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;temporarily add
&lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;## &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;deb http://packages.linuxmint.com debian import
&lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;## &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;and `contrib non-free` to /apt/sources.lisp
&lt;/span&gt;
apt-get install firmware-ralink firmware-realtek
apt-get install screen make emacs24 git gitk wicd-curses pmount htop gnupg unetbootin
apt-get install mplayer feh pacpl imagemagick x-window-system dmenu xmonad gimp inkscape firefox
apt-get install python-pip sbcl vrms

&lt;span style=&quot;color: #b22222;&quot;&gt;## &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;remove the temporary repos&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;There are a couple of changes there from my usual. Firstly, &lt;a href=&quot;https://www.mozilla.org/en-US/firefox/new/&quot;&gt;Firefox&lt;/a&gt; has become my go-to browser. Its absorbed most of the goodness from Chromium, including the reduced toolbar footprint and fantastic JS console. It also has support for adblock, and a fairly good RSS feed reader, and it&#39;s no longer slow as molasses&lt;a href=&quot;#foot-Sat-Jan-04-174337EST-2014&quot; name=&quot;note-Sat-Jan-04-174337EST-2014&quot;&gt;[3]&lt;/a&gt;. This raises the problem of the Debian packaging though; in the official repos, &lt;code&gt;apt-get install firefox&lt;/code&gt; gets you a pretty ham-fisted re-brand with no plugin support called &lt;a href=&quot;http://packages.debian.org/unstable/web/iceweasel&quot;&gt;&quot;Iceweasel&quot;&lt;/a&gt;. What I ended up doing, as you can see above, is temporarily adding the &lt;a href=&quot;http://www.linuxmint.com/&quot;&gt;Linux Mint&lt;/a&gt; repo to install that&lt;a href=&quot;#foot-Sat-Jan-04-174339EST-2014&quot; name=&quot;note-Sat-Jan-04-174339EST-2014&quot;&gt;[4]&lt;/a&gt;. Secondly, I&#39;m installing &lt;code&gt;emacs24&lt;/code&gt; rather than just plain &lt;code&gt;emacs&lt;/code&gt;. This is because the current default for &lt;code&gt;emacs&lt;/code&gt; in Jessie is Emacs 23.something, and that doesn&#39;t have one of the main features I&#39;m looking to finally adopt.&lt;/p&gt;

&lt;p&gt;Emacs 24 supports &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_node/emacs/Package-Installation.html#Package-Installation&quot;&gt;&lt;code&gt;package&lt;/code&gt;&lt;/a&gt; out of the box. In practice, this means adding&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;require&lt;/span&gt; &#39;&lt;span style=&quot;color: #008b8b;&quot;&gt;package&lt;/span&gt;)
(add-to-list &#39;package-archives &#39;(&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;melpa&quot;&lt;/span&gt; . &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;http://melpa.milkbox.net/packages/&quot;&lt;/span&gt;) t)&lt;/pre&gt;

&lt;p&gt;to my &lt;code&gt;.emacs&lt;/code&gt; instead of toting my old &lt;code&gt;.emacs.d/&lt;/code&gt; around. I can&#39;t actually remember every library I &lt;i&gt;used&lt;/i&gt; to have around, so the list I settled on this time out ended up being&lt;/p&gt;

&lt;pre&gt;aes auto-complete autopair highlight-parentheses htmlize skewer-mode magit markdown-mode paredit redo+ smart-tab yasnippet&lt;/pre&gt;

&lt;p&gt;Which covers pretty much everything. Oh, one thing. I spent about half an hour figuring out what was going wrong with my &lt;code&gt;.emacs&lt;/code&gt; config; libraries I was certain had been installed were coming back with &lt;code&gt;not found&lt;/code&gt; errors when I tried to &lt;code&gt;require&lt;/code&gt; them. It turns out that when you add a directory to the load path, you don&#39;t automatically add all its subdirectories. As you can see by the above list of packages, I use quite a few, each of which gets its own sub-directory in &lt;code&gt;.emacs.d/elpa/&lt;/code&gt;, and wildcards don&#39;t work here either. So I was forced to add the following to &lt;a href=&quot;https://github.com/Inaimathi/emacs-utils/blob/master/convenience.el&quot;&gt;convenience.el&lt;/a&gt;, just to save myself the tedium&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;starts-with-dot-p&lt;/span&gt; (path)
  (= (aref path 0) ?.))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;list-subdirectories&lt;/span&gt; (path)
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((all (mapcar 
              (&lt;span style=&quot;color: #a020f0;&quot;&gt;lambda&lt;/span&gt; (name) (concat (file-name-as-directory path) name))
              (remove-if #&#39;starts-with-dot-p (directory-files path)))))
    (remove-if-not #&#39;file-directory-p all)))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;add-to-load-path&lt;/span&gt; (dirs)
  (mapc (&lt;span style=&quot;color: #a020f0;&quot;&gt;lambda&lt;/span&gt; (p) (add-to-list &#39;load-path p)) dirs))&lt;/pre&gt;

&lt;p&gt;then called this near the top of that &lt;code&gt;.emacs&lt;/code&gt; file:&lt;/p&gt;

&lt;pre&gt;(add-to-load-path (list-subdirectories &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;~/.emacs.d/elpa&quot;&lt;/span&gt;))&lt;/pre&gt;

&lt;p&gt;This let me continue as normal. The only omission from that emacs package list is &lt;a href=&quot;http://common-lisp.net/project/slime/&quot;&gt;&lt;code&gt;slime&lt;/code&gt;&lt;/a&gt;, which I&#39;ve lately been installing from &lt;code&gt;sbcl&lt;/code&gt; or what-have-you with &lt;code&gt;(ql:quickload :quicklisp-slime-helper)&lt;/code&gt; rather than through Emacs itself. It works exactly as well as you&#39;d expect, which is to say flawlessly.&lt;/p&gt;

&lt;h3&gt;Dicking Around With Pis&lt;/h3&gt;

&lt;p&gt;Doing that got me into an installing mood, so I also formatted a fresh couple of SD cards with the latest versions of &lt;a href=&quot;http://archlinuxarm.org/platforms/armv6/raspberry-pi&quot;&gt;ARM Arch&lt;/a&gt; and &lt;a href=&quot;http://www.raspbian.org/&quot;&gt;Raspbian&lt;/a&gt; respectively. I did this with the vague intention of getting &lt;code&gt;deal&lt;/code&gt; to work with one or both, and it looks like &lt;i&gt;that&lt;/i&gt;&#39;ll take a bit more work than just a straight-up &lt;code&gt;ql:quickload&lt;/code&gt;. Differences before I get to that though.&lt;/p&gt;

&lt;p&gt;The RPi arch is much closer to what I&#39;m used to on my laptop. A brutally minimal installation of the few core utilities you need to get basic shit done, and &lt;i&gt;nothing else&lt;/i&gt;. Specifically, it gives you &lt;code&gt;pacman&lt;/code&gt;, &lt;code&gt;perl&lt;/code&gt;, a working &lt;code&gt;ssh&lt;/code&gt; server and a minimally intrusive wireless connection mechanism that could replace &lt;code&gt;wicd-curses&lt;/code&gt; for me. Raspbian, by contrast, bundles a mandatory window environment along with a bunch of crap that&#39;s probably nice for most humans looking to use it as a desktop replacement, but that I&#39;ll never end up touching. Also, they bundle Scratch as well as Python 2 &lt;i&gt;and&lt;/i&gt; 3. Finally, while they do provide an &lt;code&gt;ssh&lt;/code&gt; server, it&#39;s off by default, and the first time you boot a Raspbian image, it &lt;i&gt;forces&lt;/i&gt; &lt;code&gt;raspi-config&lt;/code&gt;, which means that you &lt;i&gt;must&lt;/i&gt; connect a Raspbian Pi to a monitor and keyboard at least once.&lt;/p&gt;

&lt;p&gt;That minimalism ends up biting Arch a bit though; it doesn&#39;t come with the standard &lt;code&gt;raspi-config&lt;/code&gt; utility, which lets you mess around with the hardware to some small extent, and easily resize the installation partition to fill the SD card&lt;a href=&quot;#foot-Sat-Jan-04-174349EST-2014&quot; name=&quot;note-Sat-Jan-04-174349EST-2014&quot;&gt;[5]&lt;/a&gt;. The other thing that bites ARM Arch in the ass, as far as I&#39;m concerned, is the fact that its package manager has very few of the things I want to install. Out of my usual menagerie, I found &lt;code&gt;screen&lt;/code&gt;, &lt;code&gt;make&lt;/code&gt;, &lt;code&gt;clisp&lt;/code&gt;, &lt;code&gt;python&lt;/code&gt;, &lt;code&gt;emacs&lt;/code&gt; and nothing else. By contrast, I had to &lt;code&gt;apt-get --purge&lt;/code&gt; a bunch of things over on Raspbian, but I &lt;i&gt;was&lt;/i&gt; eventually able to get it working with an almost copy of my laptop environment.&lt;/p&gt;

&lt;p&gt;Almost, because Lisp still has some problems.&lt;/p&gt;

&lt;p&gt;Specifically, &lt;code&gt;clisp&lt;/code&gt; segfaults on both ARM Arch &lt;i&gt;and&lt;/i&gt; Raspbian when you try to load anything with &lt;code&gt;quicklisp&lt;/code&gt;, while the ARM &lt;a href=&quot;http://ccl.clozure.com/download.html&quot;&gt;ccl&lt;/a&gt; failed to run at all on Arch&lt;a href=&quot;#foot-Sat-Jan-04-174352EST-2014&quot; name=&quot;note-Sat-Jan-04-174352EST-2014&quot;&gt;[6]&lt;/a&gt;. Raspbian &lt;i&gt;did&lt;/i&gt; run &lt;code&gt;ccl&lt;/code&gt; appropriately, but errored out on me for two reasons. Firstly, there&#39;s something unsupported about the &lt;code&gt;:ironclad&lt;/code&gt; MD5 digest, and secondly, the ARM architecture seems to treat bivalent streams differently than x86. Which means that even running its custom &lt;a href=&quot;https://github.com/Inaimathi/deal/tree/master/house&quot;&gt;&lt;code&gt;house&lt;/code&gt;&lt;/a&gt; server, &lt;code&gt;:deal&lt;/code&gt; errored out.&lt;/p&gt;

&lt;p&gt;I&#39;ll be trying to fix that over the next little while.&lt;/p&gt;

&lt;h3&gt;cl-git-fs&lt;/h3&gt;

&lt;p&gt;Finally, on a merely semi-related note, I&#39;m working on a couple of projects on my own time that are eventually going to want to do some sort of file management. And I figured it would be nice not to have to bring &lt;code&gt;git&lt;/code&gt; into it manually after the fact. To that end, I took a look at how &lt;a href=&quot;http://gitit.net/&quot;&gt;&lt;code&gt;gitit&lt;/code&gt;&lt;/a&gt; manages the trick of using git as a faux-database for its wiki pages. It&#39;s &lt;a href=&quot;http://hackage.haskell.org/package/filestore-0.3.2/docs/src/Data-FileStore-Git.html&quot;&gt;not that complicated&lt;/a&gt;, as it turns out. And &lt;a href=&quot;https://github.com/Inaimathi/cl-git-fs&quot;&gt;here&#39;s&lt;/a&gt; the result of spending an hour or two porting that piece of functionality to Common Lisp.&lt;/p&gt;

&lt;p&gt;The biggest problem I&#39;m running into is that there isn&#39;t a standard &lt;code&gt;shell-command&lt;/code&gt; or &lt;code&gt;run-program&lt;/code&gt; defined in the various Lisps I want to support.&lt;/p&gt;

&lt;p&gt;I&#39;m tossing it up to &lt;a href=&quot;https://github.com/Inaimathi&quot;&gt;my github&lt;/a&gt;, but calling it &lt;code&gt;0.01&lt;/code&gt; because there&#39;s a fuckton of functionality and documentation missing. In particular, it currently only supports SBCL on Linux, and a few of the external API functions still return raw string results, rather than properly parsed CLOS instances. The documentation and parsing will be a priority no matter what, but I&#39;ll only see how it runs on other platforms and implementations as I need to deploy to them.&lt;/p&gt;


&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Sat-Jan-04-174331EST-2014&quot; name=&quot;foot-Sat-Jan-04-174331EST-2014&quot;&gt;[back]&lt;/a&gt; - Of course, the drive box says 128G, so Samsung and all drive manufacturers are lying shitbags, but I&#39;m digressing again.&lt;/p&gt;
&lt;p&gt;2 - &lt;a href=&quot;#note-Sat-Jan-04-174334EST-2014&quot; name=&quot;foot-Sat-Jan-04-174334EST-2014&quot;&gt;[back]&lt;/a&gt; - And therefore keep drawing power until a forced shutdown.&lt;/p&gt;
&lt;p&gt;3 - &lt;a href=&quot;#note-Sat-Jan-04-174337EST-2014&quot; name=&quot;foot-Sat-Jan-04-174337EST-2014&quot;&gt;[back]&lt;/a&gt; - which it was last time I played around with it.&lt;/p&gt;
&lt;p&gt;4 - &lt;a href=&quot;#note-Sat-Jan-04-174339EST-2014&quot; name=&quot;foot-Sat-Jan-04-174339EST-2014&quot;&gt;[back]&lt;/a&gt; - No, since you ask, I&#39;ve never just straight up tried Mint. It has something in common with most of the distros I get recommended, which is that it cribs heavily from Debian on everything that matters, and then tries to differentiate on the desktop environment almost entirely. Not that this is bad for end users I guess, but as you can see from the &lt;code&gt;x-window-system&lt;/code&gt; and &lt;code&gt;xmonad&lt;/code&gt; items in that installation list above, I do not use what you would think of as &quot;a desktop environment&quot;. Don&#39;t let that stop you from trying it, of course, but &lt;i&gt;I&#39;m&lt;/i&gt; not going to.&lt;/p&gt;
&lt;p&gt;5 - &lt;a href=&quot;#note-Sat-Jan-04-174349EST-2014&quot; name=&quot;foot-Sat-Jan-04-174349EST-2014&quot;&gt;[back]&lt;/a&gt; - You can still do this externally via &lt;code&gt;gparted&lt;/code&gt; when you image your SD card.&lt;/p&gt;
&lt;p&gt;6 - &lt;a href=&quot;#note-Sat-Jan-04-174352EST-2014&quot; name=&quot;foot-Sat-Jan-04-174352EST-2014&quot;&gt;[back]&lt;/a&gt; - running the included binary gave me a &quot;wrong architecture&quot; error, even though there&#39;s no way that&#39;s accurate.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/1820640473604997502/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2014/01/debian-testing-pis-and-git.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/1820640473604997502'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/1820640473604997502'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2014/01/debian-testing-pis-and-git.html' title='Debian Testing, Pi and Git'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-7791850824059215816</id><published>2013-12-14T10:04:00.002-08:00</published><updated>2013-12-14T10:04:26.284-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Almost Literate Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="Common Lisp"/><title type='text'>Implementing Humane Authentication</title><content type='html'>&lt;p&gt;&lt;a href=&quot;http://langnostic.blogspot.ca/2013/12/jef-raskin-on-authentication.html&quot;&gt;Last time&lt;/a&gt;, I mentioned the auth system proposed by Raskin in his book &lt;a href=&quot;http://www.amazon.com/The-Humane-Interface-Directions-Interactive/dp/0201379376&quot;&gt;The Humane Interface&lt;/a&gt;. This time, lets dissect something concrete.&lt;/p&gt;

&lt;p&gt;Actually, before we get to dissecting anything, let me emphasize again that the &lt;i&gt;most&lt;/i&gt; humane approach to authentication is not requiring it. If you have a system that could be exposed to anonymous users, that&#39;s what you should do. &lt;i&gt;If&lt;/i&gt; you&#39;ve decided that you absolutely must have some sort of authentication step, then this doesn&#39;t seem to be a bad way to go.&lt;/p&gt;

&lt;p&gt;Now then...&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;raskin-auth.asd
&lt;/span&gt;(asdf:defsystem #&lt;span style=&quot;color: #7a378b;&quot;&gt;:raskin-auth&lt;/span&gt;
  &lt;span style=&quot;color: #7a378b;&quot;&gt;:serial&lt;/span&gt; t
  &lt;span style=&quot;color: #7a378b;&quot;&gt;:description&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Implementation of the authentication system proposed in The Humane Interface&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #7a378b;&quot;&gt;:author&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi &amp;lt;&lt;a href=&quot;mailto:leo.zovic&amp;#64;gmail.com&quot;&gt;leo.zovic&amp;#64;gmail.com&lt;/a&gt;&amp;gt;&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #7a378b;&quot;&gt;:license&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;AGPL, as usual&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #7a378b;&quot;&gt;:depends-on&lt;/span&gt; (#&lt;span style=&quot;color: #7a378b;&quot;&gt;:cl-ppcre&lt;/span&gt; #&lt;span style=&quot;color: #7a378b;&quot;&gt;:ironclad&lt;/span&gt;)
  &lt;span style=&quot;color: #7a378b;&quot;&gt;:components&lt;/span&gt; ((&lt;span style=&quot;color: #7a378b;&quot;&gt;:file&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;package&quot;&lt;/span&gt;)
               (&lt;span style=&quot;color: #7a378b;&quot;&gt;:file&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;util&quot;&lt;/span&gt;)
               (&lt;span style=&quot;color: #7a378b;&quot;&gt;:file&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;raskin-auth&quot;&lt;/span&gt;)))&lt;/pre&gt;

&lt;pre&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;package.lisp
&lt;/span&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defpackage&lt;/span&gt; #&lt;span style=&quot;color: #7a378b;&quot;&gt;:raskin-auth&lt;/span&gt;
  (&lt;span style=&quot;color: #7a378b;&quot;&gt;:use&lt;/span&gt; #&lt;span style=&quot;color: #7a378b;&quot;&gt;:cl&lt;/span&gt;)
  (&lt;span style=&quot;color: #7a378b;&quot;&gt;:export&lt;/span&gt; #&lt;span style=&quot;color: #7a378b;&quot;&gt;:new-account!&lt;/span&gt; #&lt;span style=&quot;color: #7a378b;&quot;&gt;:sign-in&lt;/span&gt;))&lt;/pre&gt;

&lt;pre&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;util.lisp
&lt;/span&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;in-package&lt;/span&gt; #&lt;span style=&quot;color: #7a378b;&quot;&gt;:raskin-auth&lt;/span&gt;)

&lt;span style=&quot;color: #b22222;&quot;&gt;;;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;Dictionary-related
&lt;/span&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defconstant&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;+dict+&lt;/span&gt; (coerce 
                     (&lt;span style=&quot;color: #a020f0;&quot;&gt;with-open-file&lt;/span&gt; (s &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;/usr/share/dict/american-english&quot;&lt;/span&gt;)
                       (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for line = (read-line s nil &lt;span style=&quot;color: #7a378b;&quot;&gt;:eof&lt;/span&gt;) until (eql line &lt;span style=&quot;color: #7a378b;&quot;&gt;:eof&lt;/span&gt;)
                          unless (cl-ppcre:scan &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;[&lt;/span&gt;&lt;span style=&quot;color: #8b2252;&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color: #8b2252;&quot;&gt;a-zA-Z]&quot;&lt;/span&gt; line)
                          collect (string-downcase line)))
                     &#39;vector))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;random-words&lt;/span&gt; (count &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;optional&lt;/span&gt; (dict +dict+))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; repeat count
     collect (aref dict (random (length dict)))))

&lt;span style=&quot;color: #b22222;&quot;&gt;;;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;Hash-related
&lt;/span&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;iterated-digest&lt;/span&gt; ((count integer) (digest-spec symbol) (message string))
  (&lt;span style=&quot;color: #ff0000; font-weight: bold;&quot;&gt;assert&lt;/span&gt; (&amp;gt; count 0))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; with res = (ironclad:ascii-string-to-byte-array message)
     repeat count do (setf res (ironclad:digest-sequence digest-spec res))
     finally (&lt;span style=&quot;color: #a020f0;&quot;&gt;return&lt;/span&gt; res)))&lt;/pre&gt;

&lt;pre&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;raskin-auth.lisp
&lt;/span&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;in-package&lt;/span&gt; #&lt;span style=&quot;color: #7a378b;&quot;&gt;:raskin-auth&lt;/span&gt;)

(setf *random-state* (make-random-state t))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defparameter&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;*users*&lt;/span&gt; (make-hash-table &lt;span style=&quot;color: #7a378b;&quot;&gt;:test&lt;/span&gt; &#39;equal))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;hash&lt;/span&gt; (passphrase)
  (ironclad:byte-array-to-hex-string (iterated-digest 10000 &lt;span style=&quot;color: #7a378b;&quot;&gt;:sha256&lt;/span&gt; passphrase)))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;fresh-passphrase&lt;/span&gt; ()
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((u-mod (/ (hash-table-count *users*) 100000)))
    (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for num-words = (+ 2 (floor u-mod) (random (+ 2 (ceiling u-mod))))
       for passphrase = (format nil &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;~{~(~a~)~^-~}&quot;&lt;/span&gt; (random-words num-words))
       unless (gethash passphrase *users*) do (&lt;span style=&quot;color: #a020f0;&quot;&gt;return&lt;/span&gt; passphrase))))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;new-account!&lt;/span&gt; (&lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;optional&lt;/span&gt; (user-data t))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((passphrase (fresh-passphrase)))
    (setf (gethash (hash passphrase) *users*) user-data)
    passphrase))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;sign-in&lt;/span&gt; (passphrase)
  (gethash (hash passphrase) *users*))&lt;/pre&gt;

&lt;p&gt;And that&#39;s it. In a production system, you&#39;d obviously want to wire everything up to some database system or other rather than using an in-memory hash-table, but this explains the concept well enough. You&#39;d use this module by including it, then calling &lt;code&gt;(new-account! [user account data goes here])&lt;/code&gt; (which will return a newly generated passphrase) and &lt;code&gt;(sign-in &quot;a-passphrase-goes-here&quot;)&lt;/code&gt; (which will return either &lt;code&gt;nil&lt;/code&gt; or the account data you associated with the given passphrase) as necessary.&lt;/p&gt;

&lt;p&gt;Lets go through it.&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;raskin-auth.asd
&lt;/span&gt;(asdf:defsystem #&lt;span style=&quot;color: #7a378b;&quot;&gt;:raskin-auth&lt;/span&gt;
  &lt;span style=&quot;color: #7a378b;&quot;&gt;:serial&lt;/span&gt; t
  &lt;span style=&quot;color: #7a378b;&quot;&gt;:description&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Implementation of the authentication system proposed in The Humane Interface&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #7a378b;&quot;&gt;:author&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Inaimathi &amp;lt;&lt;a href=&quot;mailto:leo.zovic&amp;#64;gmail.com&quot;&gt;leo.zovic&amp;#64;gmail.com&lt;/a&gt;&amp;gt;&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #7a378b;&quot;&gt;:license&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;AGPL, as usual&quot;&lt;/span&gt;
  &lt;span style=&quot;color: #7a378b;&quot;&gt;:depends-on&lt;/span&gt; (#&lt;span style=&quot;color: #7a378b;&quot;&gt;:cl-ppcre&lt;/span&gt; #&lt;span style=&quot;color: #7a378b;&quot;&gt;:ironclad&lt;/span&gt;)
  &lt;span style=&quot;color: #7a378b;&quot;&gt;:components&lt;/span&gt; ((&lt;span style=&quot;color: #7a378b;&quot;&gt;:file&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;package&quot;&lt;/span&gt;)
               (&lt;span style=&quot;color: #7a378b;&quot;&gt;:file&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;util&quot;&lt;/span&gt;)
               (&lt;span style=&quot;color: #7a378b;&quot;&gt;:file&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;raskin-auth&quot;&lt;/span&gt;)))&lt;/pre&gt;

&lt;pre&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;package.lisp
&lt;/span&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defpackage&lt;/span&gt; #&lt;span style=&quot;color: #7a378b;&quot;&gt;:raskin-auth&lt;/span&gt;
  (&lt;span style=&quot;color: #7a378b;&quot;&gt;:use&lt;/span&gt; #&lt;span style=&quot;color: #7a378b;&quot;&gt;:cl&lt;/span&gt;)
  (&lt;span style=&quot;color: #7a378b;&quot;&gt;:export&lt;/span&gt; #&lt;span style=&quot;color: #7a378b;&quot;&gt;:new-account!&lt;/span&gt; #&lt;span style=&quot;color: #7a378b;&quot;&gt;:sign-in&lt;/span&gt;))&lt;/pre&gt;

&lt;p&gt;That&#39;s the ASD file and package. The first makes sure you can load this system using &lt;a href=&quot;http://common-lisp.net/project/asdf/&quot;&gt;&lt;code&gt;asdf&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;http://www.quicklisp.org/beta/&quot;&gt;&lt;code&gt;quicklisp&lt;/code&gt;&lt;/a&gt;, and the second declares your imports and exports. I&#39;m trying something new this time and refusing to use &lt;code&gt;:use&lt;/code&gt; or &lt;code&gt;:import-from&lt;/code&gt; and friends. I&#39;ve gotten a couple comments to the effect that it gets a bit confusing if I import symbols directly rather than labeling them inline with the package they came from, so even though &lt;code&gt;raskin-auth&lt;/code&gt; &lt;i&gt;does&lt;/i&gt; use things from both &lt;a href=&quot;http://method-combination.net/lisp/ironclad/&quot;&gt;&lt;code&gt;ironclad&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;http://weitz.de/cl-ppcre/&quot;&gt;&lt;code&gt;cl-ppcre&lt;/code&gt;&lt;/a&gt;, the &lt;code&gt;package.lisp&lt;/code&gt; file is staying minimal.&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;util.lisp
&lt;/span&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;in-package&lt;/span&gt; #&lt;span style=&quot;color: #7a378b;&quot;&gt;:raskin-auth&lt;/span&gt;)

&lt;span style=&quot;color: #b22222;&quot;&gt;;;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;Dictionary-related
&lt;/span&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defconstant&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;+dict+&lt;/span&gt; (coerce 
                     (&lt;span style=&quot;color: #a020f0;&quot;&gt;with-open-file&lt;/span&gt; (s &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;/usr/share/dict/american-english&quot;&lt;/span&gt;)
                       (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for line = (read-line s nil &lt;span style=&quot;color: #7a378b;&quot;&gt;:eof&lt;/span&gt;) until (eql line &lt;span style=&quot;color: #7a378b;&quot;&gt;:eof&lt;/span&gt;)
                          unless (cl-ppcre:scan &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;[&lt;/span&gt;&lt;span style=&quot;color: #8b2252;&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color: #8b2252;&quot;&gt;a-zA-Z]&quot;&lt;/span&gt; line)
                          collect (string-downcase line)))
                     &#39;vector))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;random-words&lt;/span&gt; (count &lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;optional&lt;/span&gt; (dict +dict+))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; repeat count
     collect (aref dict (random (length dict)))))

&lt;span style=&quot;color: #b22222;&quot;&gt;;;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;Hash-related
&lt;/span&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defmethod&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;iterated-digest&lt;/span&gt; ((count integer) (digest-spec symbol) (message string))
  (&lt;span style=&quot;color: #ff0000; font-weight: bold;&quot;&gt;assert&lt;/span&gt; (&amp;gt; count 0))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; with res = (ironclad:ascii-string-to-byte-array message)
     repeat count do (setf res (ironclad:digest-sequence digest-spec res))
     finally (&lt;span style=&quot;color: #a020f0;&quot;&gt;return&lt;/span&gt; res)))&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;random-words&lt;/code&gt; creates a list of &lt;code&gt;count&lt;/code&gt; random words by picking them out of a dictionary, which is &lt;code&gt;+dict+&lt;/code&gt; by default. You don&#39;t necessarily want these words to be unique, so we don&#39;t check for that. &lt;code&gt;+dict+&lt;/code&gt; is just some slightly sanitized output from &lt;code&gt;/usr/share/dict/american-english&lt;/code&gt;, which is where Debian keeps the default English language dictionary. The result of that read is a &lt;code&gt;vector&lt;/code&gt; of all words in the dict file that are composed entirely of lowercase letters. What we&#39;re doing, essentially is &lt;code&gt;shuf -n [count] /usr/share/dict/american-english&lt;/code&gt;. Except we&#39;re filtering for some stuff, so that should really get piped through a &lt;code&gt;grep&lt;/code&gt; or two. Use whatever method you&#39;d like; the end goal is to get a list of &lt;code&gt;count&lt;/code&gt; random words, from a list of ~60000 different words, each with an equal probability.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;iterated-digest&lt;/code&gt; takes a &lt;code&gt;count&lt;/code&gt;, a &lt;code&gt;digest-spec&lt;/code&gt; and a &lt;code&gt;message&lt;/code&gt;, and applies the specified &lt;code&gt;digest&lt;/code&gt; to the &lt;code&gt;message&lt;/code&gt; &lt;code&gt;count&lt;/code&gt; times sequentially. We&#39;ll take a look at how you call it in a second.&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;;;;; &lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;raskin-auth.lisp
&lt;/span&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;in-package&lt;/span&gt; #&lt;span style=&quot;color: #7a378b;&quot;&gt;:raskin-auth&lt;/span&gt;)

(setf *random-state* (make-random-state t))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defparameter&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;*users*&lt;/span&gt; (make-hash-table &lt;span style=&quot;color: #7a378b;&quot;&gt;:test&lt;/span&gt; &#39;equal))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;hash&lt;/span&gt; (passphrase)
  (ironclad:byte-array-to-hex-string (iterated-digest 10000 &lt;span style=&quot;color: #7a378b;&quot;&gt;:sha256&lt;/span&gt; passphrase)))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;fresh-passphrase&lt;/span&gt; ()
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((u-mod (/ (hash-table-count *users*) 100000)))
    (&lt;span style=&quot;color: #a020f0;&quot;&gt;loop&lt;/span&gt; for num-words = (+ 2 (floor u-mod) (random (+ 2 (ceiling u-mod))))
       for passphrase = (format nil &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;~{~(~a~)~^-~}&quot;&lt;/span&gt; (random-words num-words))
       unless (gethash passphrase *users*) do (&lt;span style=&quot;color: #a020f0;&quot;&gt;return&lt;/span&gt; passphrase))))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;new-account!&lt;/span&gt; (&lt;span style=&quot;color: #228b22;&quot;&gt;&amp;amp;optional&lt;/span&gt; (user-data t))
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((passphrase (fresh-passphrase)))
    (setf (gethash (hash passphrase) *users*) user-data)
    passphrase))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;sign-in&lt;/span&gt; (passphrase)
  (gethash (hash passphrase) *users*))&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;*users*&lt;/code&gt; is a hash table that&#39;ll keep all of our user records&lt;a href=&quot;#foot-Sat-Dec-14-125727EST-2013&quot; name=&quot;note-Sat-Dec-14-125727EST-2013&quot;&gt;[1]&lt;/a&gt;, and both &lt;code&gt;new-account!&lt;/code&gt; and &lt;code&gt;sign-in&lt;/code&gt; are hopefully self explanatory. Let me linger on the rest of that though.&lt;/p&gt;

&lt;p&gt;First, you absolutely positively need the &lt;code&gt;*random-state*&lt;/code&gt; initialization. Without that line, your system will generate the same order of passphrases each time it starts up. Maybe that&#39;s not too big a deal in general, but I&#39;m paranoid enough that I want proper, os-seeded randomness out when I&#39;m generating authentication tokens.&lt;/p&gt;

&lt;p&gt;Second, you can see the &lt;code&gt;iterated-digest&lt;/code&gt; call here:&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;defun&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;hash&lt;/span&gt; (passphrase)
  (ironclad:byte-array-to-hex-string (iterated-digest 10000 &lt;span style=&quot;color: #7a378b;&quot;&gt;:sha256&lt;/span&gt; passphrase)))&lt;/pre&gt;

&lt;p&gt;That takes a particular &lt;code&gt;passphrase&lt;/code&gt; string and returns the result of applying the &lt;code&gt;:sha256&lt;/code&gt; digest to it 10000 times. I guess you could make that &lt;code&gt;:sha512&lt;/code&gt; if you really wanted to.&lt;/p&gt;

&lt;p&gt;Finally, &lt;code&gt;fresh-passphrase&lt;/code&gt; does the job of calling &lt;code&gt;random-words&lt;/code&gt;, concatenating the result, and checking whether the result of &lt;i&gt;that&lt;/i&gt; is already on record. It keeps going until it generates a passphrase that no one else is using at the moment, and returns that. You can see that it scales somewhat with count of users registered, just to make sure we don&#39;t get into the situation where a particular passphrase length is particularly easy to guess.&lt;/p&gt;

&lt;p&gt;That&#39;s it. Again, what I see here is reasonable security.&lt;/p&gt;

&lt;h3&gt;Thoughts&lt;/h3&gt;

&lt;p&gt;On the one hand, you don&#39;t get to salt passphrase hashes. Which means that if anyone manages to trick a user of this auth system into revealing their ciphertexts, they&#39;ll have a mildly easier time cracking the result. And, since every passphrase is unique, they can knock out some tiny number of possibilities as they go. You also can&#39;t easily change your hashing tactic in-flight. Hypothetically, if you chose the iterated &lt;code&gt;:sha256&lt;/code&gt; approach from above, and it then turned out that clever people found ways to compromise that hash, you wouldn&#39;t be able to switch your tactics on a live system easily, the way you could with a user-name-oriented system. You &lt;i&gt;would&lt;/i&gt; be able to increase the number of hashings fairly easily; just modify your &lt;code&gt;hash&lt;/code&gt; to do more iterations, and modify your registered users&#39; passwords to make up the difference.&lt;/p&gt;

&lt;p&gt;On the &lt;i&gt;other&lt;/i&gt; hand, no one will ever have the passphrase &lt;code&gt;123&lt;/code&gt; with this system. And, since they didn&#39;t pick it, they presumably won&#39;t have this same passphrase on any other service they frequent, which means a compromise here won&#39;t have to result in a mad dash to change their account passwords anywhere else fo fear of &lt;a href=&quot;http://xkcd.com/792/&quot;&gt;exploits&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The only other downsides seem to be that you can&#39;t choose a passphrase, and that if you forget your passphrase, you must create a new account.&lt;/p&gt;



&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Sat-Dec-14-125727EST-2013&quot; name=&quot;foot-Sat-Dec-14-125727EST-2013&quot;&gt;[back]&lt;/a&gt; -  &lt;i&gt;Because&lt;/i&gt; it&#39;s a hash table, and I don&#39;t bother doing any kind of locking, the system you see specified here very likely won&#39;t do for any multi-threaded use-cases. You can either add locks, or go the whole nine and replace that hash table with an external database, but I don&#39;t need either to see the basic properties of the system, so I didn&#39;t implement them.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/7791850824059215816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2013/12/implementing-humane-authentication.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/7791850824059215816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/7791850824059215816'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2013/12/implementing-humane-authentication.html' title='Implementing Humane Authentication'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-2482391454987160105</id><published>2013-12-10T10:16:00.001-08:00</published><updated>2013-12-10T14:00:22.077-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Common Lisp"/><category scheme="http://www.blogger.com/atom/ns#" term="Idea Peeling"/><category scheme="http://www.blogger.com/atom/ns#" term="Speculation"/><title type='text'>Jef Raskin on Authentication</title><content type='html'>&lt;p&gt;I&#39;ve got an idea to peel, and for a change, it&#39;s not even mine. I&#39;m in the middle of reading through a &lt;a href=&quot;https://en.wikipedia.org/wiki/Jef_Raskin&quot;&gt;Raskin&lt;/a&gt; book entitled &lt;a href=&quot;http://www.amazon.com/The-Humane-Interface-Directions-Interactive/dp/0201379376&quot;&gt;&quot;The Humane Interface&quot;&lt;/a&gt;, in which he suggests a different take on user authentication. In section &lt;b&gt;6-4-3&lt;/b&gt;&lt;a href=&quot;#foot-Tue-Dec-10-132000EST-2013&quot; name=&quot;note-Tue-Dec-10-132000EST-2013&quot;&gt;[1]&lt;/a&gt;, Raskin suggests that signing on to a system can be accomplished without requiring a user name. That is, instead of ... you know what, here, this is easier:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Users are doing more work than necessary when signing on to most systems. You first state who you are -- your &quot;handle&quot;, &quot;online name&quot; or &quot;system name&quot; -- and then you provide a password. The name presumably tells the system who you are, and the password prevents unauthorized persons from using your account.&lt;/p&gt;
  &lt;p&gt;In fact, you are telling the system who you are twice. All that is logically required is that you type a password. There is no loss of system security: The probability of guessing someone&#39;s name and password depends on how the password was chosen, its length and the like. Finding the user&#39;s online name is usually trivial; in fact, it is commonly made public so that she can be communicated with. A badly chosen password, such as your dog&#39;s name, is the most common reason for poor security.&lt;/p&gt;
  &lt;p&gt;The technical argument that typing two separate strings of characters gives more security is false. If the online name is &lt;i&gt;j&lt;/i&gt; characters and the password is &lt;i&gt;k&lt;/i&gt; characters, the user, to sign on, must type &lt;i&gt;j+k&lt;/i&gt; characters, of which only &lt;i&gt;k&lt;/i&gt; characters are unknown to a potential interloper. If the password was chosen randomly -- this is the best you can do -- from a character set with &lt;i&gt;q&lt;/i&gt; characters, the probability of breaking into the account on a single guess is &lt;i&gt;1 / q^k&lt;/i&gt;.&lt;/p&gt;
  &lt;span class=&quot;sig&quot;&gt;Jef Raskin -- The Humane Interface, p183&lt;/span&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you&#39;ve given authentication systems anywhere near as much thought as I have, the trouble you should immediately see is that in a system like the one proposed above, &lt;i&gt;a password must be unique to a user&lt;/i&gt;. Luckily, Raskin sees that one coming.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The question arises: How can you ensure that everybody has a unique password in a password-only system? What if two or more users chose the same password? The best option is to have the system assign them. This method can result in very unmemorable passwords, such as &lt;code&gt;2534-788834-003PR7&lt;/code&gt; or &lt;code&gt;ty6*&amp;gt;fj`d%d&lt;/code&gt;&lt;a href=&quot;#foot-Tue-Dec-10-132003EST-2013&quot; name=&quot;note-Tue-Dec-10-132003EST-2013&quot;&gt;[2]&lt;/a&gt;. Another technique is to use a random pair of dictionary words, such as &lt;i&gt;demijohn-shoestring&lt;/i&gt;, &lt;i&gt;confirmed-tweezers&lt;/i&gt; or &lt;i&gt;sulphur-dive&lt;/i&gt;. If a dictionary of 60,000 words is used, the chance of guessing a password on the first try is one in three billion, six-hundred thousand. Using three words puts the difficulty of guessing them beyond hacking with current technology; there are 2.16 x 10^14&lt;/p&gt; such combinations, and guessing and checking a billion of these a day, beyond what can be done at present, would still take about 10^5 days, or 275 years. That&#39;s reasonably secure. User-created passwords, at least those more readily memorized by the user, are inherently less secure.&lt;/p&gt;
  &lt;p&gt;When the idea of improving the interface to a web site or a computer system by simplifying the sign-on process to require only a password is suggested, it is usually rejected on one of two grounds. Either the programmers say that that&#39;s just not the way it&#39;s done, or they say that they have no control over the sign-on procedure. But someone, of course, does have that control.&lt;/p&gt;
  &lt;span class=&quot;sig&quot;&gt;Jef Raskin -- The Humane Interface, p183,184&lt;/span&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before I discuss this idea with my self, I have to disagree with two points. First, the odds of guessing a correct password on the first try is &lt;i&gt;not&lt;/i&gt; &lt;code&gt;1&lt;/code&gt; in &lt;code&gt;3 600 000 000&lt;/code&gt;, or &lt;code&gt;1&lt;/code&gt; in &lt;code&gt;(* 2.16 (expt 10 14))&lt;/code&gt;&lt;a href=&quot;#foot-Tue-Dec-10-132008EST-2013&quot; name=&quot;note-Tue-Dec-10-132008EST-2013&quot;&gt;[3]&lt;/a&gt;. It&#39;s &lt;code&gt;n&lt;/code&gt; in whichever-you-picked, where &lt;code&gt;n&lt;/code&gt; is the number of users you have. &lt;i&gt;With a password-only system, an attacker is no longer trying to guess a particular users&#39; password, they are trying to guess &lt;b&gt;any&lt;/b&gt; password already assigned by your system.&lt;/i&gt; Second, I&#39;m not entirely sure that badly chosen passwords are any longer the most common reason for poor security&lt;a href=&quot;#foot-Tue-Dec-10-132011EST-2013&quot; name=&quot;note-Tue-Dec-10-132011EST-2013&quot;&gt;[4]&lt;/a&gt;, but rather &lt;a href=&quot;http://www.zdnet.com/ubuntu-forums-hacked-1-82m-logins-email-addresses-stolen-7000018336/&quot;&gt;utterly&lt;/a&gt;, &lt;a href=&quot;http://www.informationweek.com/attacks/sony-hacked-again-1-million-passwords-exposed/d/d-id/1098113?print=yes&quot;&gt;mind-fuckingly&lt;/a&gt; stupid security design by password DB teams&lt;a href=&quot;#foot-Tue-Dec-10-132014EST-2013&quot; name=&quot;note-Tue-Dec-10-132014EST-2013&quot;&gt;[5]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With that our of the way, lets all don our white hats&lt;a href=&quot;#foot-Tue-Dec-10-132022EST-2013&quot; name=&quot;note-Tue-Dec-10-132022EST-2013&quot;&gt;[6]&lt;/a&gt;, and imagine the proposed system in enough detail to implement it.&lt;/p&gt;

&lt;h3&gt;How does a user log in?&lt;/h3&gt;

&lt;p&gt;In the context of a web application, they&#39;ve got one field to fill out, &quot;passphrase&quot;, and one button to click, &quot;Log In&quot;. The passphrase entered is then hashed and looked up in our user database; if it matches a passphrase hash we have on file, the user ID is retrieved and used to get the specified users&#39; program state. We then continue along letting them do what they&#39;re actually here to do. In an ideal system, this authentication step would be entirely optional, allowing it to happen at the last possible moment, when a user needed to commit some piece of data to their server-side corpus.&lt;/p&gt;

&lt;p&gt;This is easily the biggest introduced weakness I see in the proposed system. Because we only have a passphrase to work with, we can only use either an unsalted hash, or a per-server &quot;salt&quot; to keep our passphrases out of plaintext. If we didn&#39;t, that user lookup based on the password would take a long time. Scaling at &lt;code&gt;On&lt;/code&gt; with number of users, with some fairly ridiculous constants tacked on. That&#39;s dangerous, because we&#39;re suddenly gambling that the rest of the application our auth system is embedded in won&#39;t allow any injection attacks, or leak database information any other way. Granted, because we&#39;re guaranteed to have unique passwords, such a disclosure isn&#39;t as easy to take advantage of as it might be, but it&#39;s still a concern.&lt;/p&gt;

&lt;h3&gt;What happens when the user enters a passphrase that isn&#39;t currently assigned?&lt;/h3&gt;

&lt;p&gt;There are really only two reasonable possibilities:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;They get an artificial delay, followed by the above message.&lt;/b&gt; The standard log-in procedure also needs to have an equivalent delay, otherwise attackers might abort a guess before getting the response back, which would prevent them from actually being delayed in the practical sense. It doesn&#39;t have to be long; a second or two would be enough to prevent the kind of guess hammering I&#39;ve got in mind, and it wouldn&#39;t be too annoying to users provided we put in a little spinning graphic in the meanwhile&lt;a href=&quot;#foot-Tue-Dec-10-132024EST-2013&quot; name=&quot;note-Tue-Dec-10-132024EST-2013&quot;&gt;[7]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;They get a &quot;logged in&quot; response with the default state in place, and no other warning.&lt;/b&gt; Effectively, an &quot;incorrect&quot; passphrase entry becomes a registration. Users might get annoyed at this one, since it would seem at first that their program state is gone.&lt;/p&gt;

&lt;p&gt;Having thought about this for a bit, it becomes clear that there&#39;s only &lt;i&gt;one&lt;/i&gt; reasonable possibility, and it&#39;s the first one.&lt;/p&gt;

&lt;h3&gt;How does the registration process work?&lt;/h3&gt;

&lt;p&gt;This might be context sensitive by application. For instance, &lt;a href=&quot;https://github.com/Inaimathi/deal&quot;&gt;Deal&lt;/a&gt; lets users play entirely anonymously. I can easily imagine a system wherein after 10 minutes of play time, a user just automatically got an in-game notice with a passphrase that would let them resume where they were. Because the server controls all the steps to a registration, it can happen behind the scenes with some game time effectively taking the place of a &lt;a href=&quot;http://www.google.com/recaptcha&quot;&gt;Captcha&lt;/a&gt;. This could be used with any system that lets you start off anonymously; wikis, bulletin boards, forums, etc.&lt;/p&gt;

&lt;p&gt;That system, elegant as it might be from the implementation and usability side of things, wouldn&#39;t work for something like &lt;a href=&quot;https://github.com/Inaimathi/goget&quot;&gt;GoGet&lt;/a&gt;. Where the only possible reason to use the application is to go back later and check what you put in the first time. In that situation, you&#39;d want the usual up-front &quot;Register&quot; button that would do the Captcha thing to make sure you&#39;re not a robot&lt;a href=&quot;#foot-Tue-Dec-10-132028EST-2013&quot; name=&quot;note-Tue-Dec-10-132028EST-2013&quot;&gt;[8]&lt;/a&gt;, and hand the user an account before they start doing stuff. Really, this might be re-designed too though; have the system start you off on a blank check-list, with an unobtrusive &quot;Log In&quot; form at the top of the page, with the added button &quot;Save&quot;, which would register you and hand you a passphrase with which you could access the list you just made.&lt;/p&gt;

&lt;h3&gt;What do we do when passphrase exhaustion occurs&lt;/h3&gt;

&lt;p&gt;Granted, 216 000 000 000 000 is a large number, but it&#39;s not infinite, which means some clever bastard out there is going to find a way to cut it in half a few times for the purposes of guessing. And it doesn&#39;t take very many halvings to get that down to a tractable level. We have to deal with this problem a good deal sooner than &quot;passphrase exhaustion&quot;; if we get to the point where all passphrases are assigned, an attacker suddenly gets access to an account no matter which possibility they guess. But if we did something naive like hand out 2-word passphrases until they ran out, then an attacker who registers and receives a 3-word passphrase would know that any 2-word combination of our dictionary words will give them access to an existing account. We&#39;d really want to generate new passphrases well before we ran out; at something like 10% exhaustion at a guess. Or better yet, don&#39;t limit passphrase length to two words, make it &lt;code&gt;n&lt;/code&gt; random words, where &lt;code&gt;n&lt;/code&gt; is something like&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; ((u-mod (/ user-count 1000000)))
  (random (+ 2 (floor u-mod)) (+ 4 (ceiling u-mod))))&lt;/pre&gt;

&lt;p&gt;That should give attackers less purchase, and scale naturally with additional users.&lt;/p&gt;

&lt;h3&gt;What Have We Got?&lt;/h3&gt;

&lt;p&gt;Switching briefly over to my black hat, I can&#39;t see an attack on this system that would get you any traction above and beyond traditional password-based implementations&lt;a href=&quot;#foot-Tue-Dec-10-132038EST-2013&quot; name=&quot;note-Tue-Dec-10-132038EST-2013&quot;&gt;[9]&lt;/a&gt;. That doesn&#39;t mean there isn&#39;t a way, of course. I&#39;ll present the idea to some discerning and devious thinkers to see what they can come up with. Otherwise, we&#39;ve got some interesting properties here, mainly because the server-side is the one putting everything together. We have a passphrase system that&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;only requires the barest interaction with the user&lt;/li&gt;
  &lt;li&gt;can be initiated automatically at some point&lt;a href=&quot;#foot-Tue-Dec-10-132043EST-2013&quot; name=&quot;note-Tue-Dec-10-132043EST-2013&quot;&gt;[10]&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;will not suffer the failure mode that someone will use this same passphrase everywhere&lt;a href=&quot;#foot-Tue-Dec-10-132046EST-2013&quot; name=&quot;note-Tue-Dec-10-132046EST-2013&quot;&gt;[11]&lt;/a&gt;, meaning that even if the system is compromised, all an attacker has is access to an account for one particular service&lt;/li&gt;
  &lt;li&gt;will never have to worry about a passphrase as shitty as &quot;password&quot; or &quot;12345&quot;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the flipside, though:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You can&#39;t change your passphrase to something you want&lt;/li&gt;
  &lt;li&gt;There isn&#39;t a way to recover or reset a forgotten passphrase&lt;a href=&quot;#foot-Tue-Dec-10-132049EST-2013&quot; name=&quot;note-Tue-Dec-10-132049EST-2013&quot;&gt;[12]&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All in all, barring someone pointing out some egregious security flaw in this approach, it seems to be worth implementing.&lt;/p&gt;

&lt;p&gt;I&#39;ll see what I can do.&lt;/p&gt;

&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Tue-Dec-10-132000EST-2013&quot; name=&quot;foot-Tue-Dec-10-132000EST-2013&quot;&gt;[back]&lt;/a&gt; - Starting on pg 183 in the copy I&#39;m holding.&lt;/p&gt;

&lt;p&gt;2 - &lt;a href=&quot;#note-Tue-Dec-10-132003EST-2013&quot; name=&quot;foot-Tue-Dec-10-132003EST-2013&quot;&gt;[back]&lt;/a&gt; - The actual printed second password contains some unicode characters which were not accurately reproduced here.&lt;/p&gt;

&lt;p&gt;3 - &lt;a href=&quot;#note-Tue-Dec-10-132008EST-2013&quot; name=&quot;foot-Tue-Dec-10-132008EST-2013&quot;&gt;[back]&lt;/a&gt; - Depending on how many words you decide to pack into each generated password.&lt;/p&gt;

&lt;p&gt;4 - &lt;a href=&quot;#note-Tue-Dec-10-132011EST-2013&quot; name=&quot;foot-Tue-Dec-10-132011EST-2013&quot;&gt;[back]&lt;/a&gt; - Though it may just be a media imparted bias on my part.&lt;/p&gt;

&lt;p&gt;5 - &lt;a href=&quot;#note-Tue-Dec-10-132014EST-2013&quot; name=&quot;foot-Tue-Dec-10-132014EST-2013&quot;&gt;[back]&lt;/a&gt; - Such as the refusal to use appropriate hashing algorithms, or inadvertent opening of various injection attacks.&lt;/p&gt;

&lt;p&gt;6 - &lt;a href=&quot;#note-Tue-Dec-10-132022EST-2013&quot; name=&quot;foot-Tue-Dec-10-132022EST-2013&quot;&gt;[back]&lt;/a&gt; - Mine&#39;s a tuque because it&#39;s cold out and I&#39;m in Canada, but you should feel free to don your hacking fedora, trilby, stetson, what-have-you as regionally appropriate.&lt;/p&gt;

&lt;p&gt;7 - &lt;a href=&quot;#note-Tue-Dec-10-132024EST-2013&quot; name=&quot;foot-Tue-Dec-10-132024EST-2013&quot;&gt;[back]&lt;/a&gt; - Most authentication systems I interact with take longer anyhow.&lt;/p&gt;

&lt;p&gt;8 - &lt;a href=&quot;#note-Tue-Dec-10-132028EST-2013&quot; name=&quot;foot-Tue-Dec-10-132028EST-2013&quot;&gt;[back]&lt;/a&gt; - Or not, really. Depending on how much traffic your system can handle, how much you care about preserving disk spce, and whether you give your users the ability to use SMTP facilities, you might get away with putting in an artificial 3 or 4 second delay before registration completes rather than trying to prevent automatic sign-ups. That&#39;s what I plan to do, in any case.&lt;/p&gt;

&lt;p&gt;9 - &lt;a href=&quot;#note-Tue-Dec-10-132038EST-2013&quot; name=&quot;foot-Tue-Dec-10-132038EST-2013&quot;&gt;[back]&lt;/a&gt; - Apart from the situation where our ciphertext passwords have been leaked. Which, granted, isn&#39;t a high bar, but still.&lt;/p&gt;

&lt;p&gt;10 - &lt;a href=&quot;#note-Tue-Dec-10-132043EST-2013&quot; name=&quot;foot-Tue-Dec-10-132043EST-2013&quot;&gt;[back]&lt;/a&gt; - As in the situation in Deal that would automatically hand the user a passphrase ~10 into active use of an unregistered account.&lt;/p&gt;

&lt;p&gt;11 - &lt;a href=&quot;#note-Tue-Dec-10-132046EST-2013&quot; name=&quot;foot-Tue-Dec-10-132046EST-2013&quot;&gt;[back]&lt;/a&gt; - Hopefully, at least.&lt;/p&gt;

&lt;p&gt;12 - &lt;a href=&quot;#note-Tue-Dec-10-132049EST-2013&quot; name=&quot;foot-Tue-Dec-10-132049EST-2013&quot;&gt;[back]&lt;/a&gt; - Since the passphrase acts as both a name and password, if you forget it, you just have to start a new account. Allowing the user to save as much of their data as possible locally would work to alleviate some of the pain from this.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/2482391454987160105/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2013/12/jef-raskin-on-authentication.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/2482391454987160105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/2482391454987160105'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2013/12/jef-raskin-on-authentication.html' title='Jef Raskin on Authentication'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-2459925594803229659</id><published>2013-12-01T19:55:00.002-08:00</published><updated>2013-12-01T19:57:51.737-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Common Lisp"/><category scheme="http://www.blogger.com/atom/ns#" term="Journal"/><title type='text'>Quick Update on Deal</title><content type='html'>&lt;p&gt;&lt;a href=&quot;https://github.com/Inaimathi/deal&quot;&gt;Deal&lt;/a&gt; proceeds apace.&lt;/p&gt;

&lt;p&gt;I&#39;ve spent the past while putting together a minimal, single-threaded asynchronous server to simplify the deployment process. Almost done, and you can see the progress on &lt;a href=&quot;https://github.com/Inaimathi/deal/tree/house-server-port&quot;&gt;this branch&lt;/a&gt; in &lt;a href=&quot;https://github.com/Inaimathi/deal/tree/house-server-port/house&quot;&gt;this subdirectory&lt;/a&gt;. The remaining stuff left ToDo is:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Better Errors.&lt;/b&gt; I need to put together an appropriate assertion mechanism. Straight up &lt;code&gt;assert&lt;/code&gt; works fine in a multi-threaded context, but does some mean things when you&#39;ve only got the one thread. Normally, it wouldn&#39;t be that big a deal, but I have to special-case my &lt;code&gt;handler-case&lt;/code&gt; statements for &lt;code&gt;SIMPLE-ERROR&lt;/code&gt; in order to allow shell interruption. Unfortunately, they&#39;re both conditions of type &lt;code&gt;simple-error&lt;/code&gt;, which means that if I do it naively, I either let both or neither through. What I&#39;m planning to do is define a macro named something like &lt;code&gt;http-assert&lt;/code&gt;, which will throw a type of error I can then safely convert into &lt;a href=&quot;http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_Error&quot;&gt;an HTTP-&lt;code&gt;400&lt;/code&gt; response&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Basic Static Files.&lt;/b&gt; Currently, I&#39;m serving static files through &lt;code&gt;nginx&lt;/code&gt; only. Which is the efficient way of doing it. However, one use-case I&#39;m thinking of for Deal is that of a small, geographically disparate team setting up a private server for themselves. It&#39;s kind of a pain in the ass to have to set up a reverse proxy for that situation, so it would be nice if &lt;a href=&quot;https://github.com/Inaimathi/deal/tree/house-server-port/house&quot;&gt;House&lt;/a&gt; provided a basic file handler for people to use.&lt;/p&gt;

&lt;p&gt;That&#39;s ... going to get complicated though. A first crack at the implementation is &lt;a href=&quot;https://github.com/Inaimathi/deal/blob/house-server-port/house/util.lisp#L54-L90&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://github.com/Inaimathi/deal/blob/house-server-port/house/house.lisp#L196-L220&quot;&gt;here&lt;/a&gt;. That only works for text files so far&lt;a href=&quot;#foot-Sun-Dec-01-230324EST-2013&quot; name=&quot;note-Sun-Dec-01-230324EST-2013&quot;&gt;[1]&lt;/a&gt;, and it only works for a laughably small number of mimetypes. A more complete map can be found &lt;a href=&quot;http://www.stdicon.com/mimetypes&quot;&gt;here&lt;/a&gt; or &lt;a href=&quot;http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/docs/conf/mime.types?view=annotate&quot;&gt;here&lt;/a&gt;, but I&#39;m not going to be anywhere near as thorough; remember, this is an edge case. This lightweight server is &lt;i&gt;not&lt;/i&gt; in the business of serving out static files in an efficient manner. &lt;i&gt;That&#39;s&lt;/i&gt; what things like &lt;code&gt;nginx&lt;/code&gt; are for, and I&#39;ve got no doubt they&#39;re doing a better job than I could.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Touch Ups&lt;/b&gt; Sessions don&#39;t expire yet. And when they do, I&#39;ll want to give them the same kind of behavior hooks that I&#39;ve got going for &lt;code&gt;new-session&lt;/code&gt;. There&#39;s also the non-trivial matter of porting the rest of the Deal system to work better with the House server, but I get the feeling I&#39;m most of the way there already.&lt;/p&gt;

&lt;p&gt;Famous last words, right?&lt;/p&gt;


&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Sun-Dec-01-230324EST-2013&quot; name=&quot;foot-Sun-Dec-01-230324EST-2013&quot;&gt;[back]&lt;/a&gt; - I&#39;m still trying to iron out kinks; in particular there seems to be some kind of character encoding issue left in the way that I just can&#39;t get my head around. I&#39;ll be &lt;a href=&quot;http://stackoverflow.com/questions/20320540/serving-static-files-with-common-lisp&quot;&gt;asking on SO&lt;/a&gt; shortly.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/2459925594803229659/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2013/12/quick-update-on-deal.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/2459925594803229659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/2459925594803229659'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2013/12/quick-update-on-deal.html' title='Quick Update on Deal'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-8832774859243474568</id><published>2013-11-30T12:26:00.000-08:00</published><updated>2013-12-01T18:49:54.267-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Common Lisp"/><category scheme="http://www.blogger.com/atom/ns#" term="HTML"/><category scheme="http://www.blogger.com/atom/ns#" term="HTML5"/><category scheme="http://www.blogger.com/atom/ns#" term="Idea Peeling"/><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming Interfaces"/><title type='text'>Combining SVG and HTML5 is still a Drag</title><content type='html'>&lt;p&gt;Dragging SVG elements is harder than it might appear at first glance.&lt;/p&gt;

&lt;p&gt;The underlying implementation of the SVG DOM and the HTML DOM is different in current browsers you see, so the standard HTML5 drag event doesn&#39;t apply to SVG nodes. Luckily, &lt;code&gt;mousedown&lt;/code&gt;, &lt;code&gt;mousemove&lt;/code&gt; and &lt;code&gt;mouseup&lt;/code&gt; &lt;i&gt;are&lt;/i&gt; supported, so you&#39;d think it would be a straight-forward task to implement the fucker yourself. You probably imagine, as I did initially, something that takes a selector and a list of callbacks, and implements something similar to jQuery&#39;s &lt;code&gt;.draggable()&lt;/code&gt; in ~30 lines of code by&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;binding a callback to the targets&#39; &lt;code&gt;mousedown&lt;/code&gt;, &lt;code&gt;mousemove&lt;/code&gt;, &lt;code&gt;mouseup&lt;/code&gt; events&lt;/li&gt;
  &lt;li&gt;storing the initial position of the element, and its delta from the mouse cursor&lt;/li&gt;
  &lt;li&gt;preventing default on &lt;code&gt;mousedown&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;in addition to firing the callback, moving the target element by manipulating &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; coordinates using the current mouse position, initial delta and initial position&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Maybe that&#39;s possible for the simple cases, but it&#39;s the edges that&#39;ll get you. And unless an implementation happens to dull all &lt;i&gt;your&lt;/i&gt; edges, it&#39;s not really good enough.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Minor speed-bump.&lt;/b&gt; What if you need to drag multiple elements? If you were dealing with HTML elements, it wouldn&#39;t be such a big deal, but SVG elements have different properties to represent their coordinates. Rectangles and similar have an &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; that represents their top-left corner, circles and ellipses have &lt;code&gt;cx&lt;/code&gt; and &lt;code&gt;cy&lt;/code&gt; that represents their center, text elements have an &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;, but theirs represents the &lt;i&gt;bottom&lt;/i&gt;-left coordinate, and I&#39;m not even getting into the path elements. Bottom line, if you want to implement something that works, you&#39;re using &lt;code&gt;transform&lt;/code&gt; settings. Also, you&#39;re not doing it naively through &lt;code&gt;setAttribute&lt;/code&gt;, unless you&#39;re lucky enough to have a situation where you can guarantee that no other transformations will be applied to any draggable element&lt;a href=&quot;#foot-Sat-Nov-30-122522EST-2013&quot; name=&quot;note-Sat-Nov-30-122522EST-2013&quot;&gt;[1]&lt;/a&gt;. The snippet that handles that particular piece looks like this in my codebase&lt;/p&gt;

&lt;pre&gt;(defpsmacro =translate (elem/s dx dy)
  `(try 
    (=&amp;gt;&amp;gt; ,elem transform base-val (get-item 0) (set-translate ,dx ,dy))
    (&lt;span style=&quot;color: #7a378b;&quot;&gt;:catch&lt;/span&gt; (&lt;span style=&quot;color: #ff0000; font-weight: bold;&quot;&gt;error&lt;/span&gt;)
      (=set-attribute ,elem &lt;span style=&quot;color: #7a378b;&quot;&gt;:transform&lt;/span&gt; (+ &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;translate(&quot;&lt;/span&gt; ,dx &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;,&quot;&lt;/span&gt; ,dy &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;)&quot;&lt;/span&gt;)))))&lt;/pre&gt;

&lt;p&gt;If you&#39;re one of the sad bastards who don&#39;t have macros at their disposal, I guess you&#39;re doing that or something fairly similar manually&lt;a href=&quot;#foot-Sat-Nov-30-122530EST-2013&quot; name=&quot;note-Sat-Nov-30-122530EST-2013&quot;&gt;[2]&lt;/a&gt;. Like I said though, no big deal either way.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Medium sized speedbump.&lt;/b&gt; If you want to do this on an arbitrarily sized element, specifically a very small one, you&#39;ll discover that moving your cursor at even moderate speeds is enough to escape from the &lt;code&gt;mousemove&lt;/code&gt; event and leave your draggable behind. One possible solution here is to also bind the &lt;code&gt;mouseleave&lt;/code&gt; event and hope you never need to move fast enough to escape that too. Another approach is to have your chosen &lt;code&gt;mousedown&lt;/code&gt; set up a &lt;i&gt;global&lt;/i&gt; &lt;code&gt;mousemove&lt;/code&gt; event, on &lt;code&gt;body&lt;/code&gt; or &lt;code&gt;html&lt;/code&gt;, use that to drag your element around, and have a global &lt;code&gt;mouseup&lt;/code&gt; waiting to cut it off as soon as you&#39;re done&lt;a href=&quot;#foot-Sat-Nov-30-122532EST-2013&quot; name=&quot;note-Sat-Nov-30-122532EST-2013&quot;&gt;[3]&lt;/a&gt;. A bit hacky, but doable.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Slightly larger speedbump.&lt;/b&gt; If you want to make these bindings switchable, you&#39;re in for a bit of a harder time. Not switchable as in &quot;different objects should be able to do mildly  different things&quot;, that&#39;s a given. I mean like &quot;it should be possible to jump into a separate interaction mode where the same object does something mildly or wildly different under certain circumstances&quot;. If you want that, you need a level of indirection in your listener tree that you can swap out with other functions, and that level of indirection is going to be calling an externally specified function on each event trigger. Basically, you&#39;ll want to be working with hooks rather than listeners at this point&lt;a href=&quot;#foot-Sat-Nov-30-122536EST-2013&quot; name=&quot;note-Sat-Nov-30-122536EST-2013&quot;&gt;[4]&lt;/a&gt;. I&#39;ll keep you posted on how this one goes in real life.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Large speedbump.&lt;/b&gt; Suppose you want to be able to use your dragging events, &lt;i&gt;and&lt;/i&gt; a &lt;code&gt;mouseup&lt;/code&gt; event on the same element. Better yet, suppose you wanted to implement &lt;code&gt;drag&lt;/code&gt;/&lt;code&gt;mousedown&lt;/code&gt; interactions, but let the user decide what layer to apply them on at any given time. Imagine a situation where you had the elements &lt;code&gt;foo&lt;/code&gt;, overlapping &lt;code&gt;bar&lt;/code&gt;, overlapping &lt;code&gt;baz&lt;/code&gt;, and when a &lt;code&gt;drag&lt;/code&gt; or &lt;code&gt;mousedown&lt;/code&gt; hits, you want to let the user decide whether they want to be &lt;code&gt;click&lt;/code&gt;/&lt;code&gt;drag&lt;/code&gt;ging &lt;code&gt;foo&lt;/code&gt; and/or &lt;code&gt;bar&lt;/code&gt; and/or &lt;code&gt;baz&lt;/code&gt;. Near I can tell, there is no way of implementing this elegantly in terms of listeners on individual elements. What you need if you want this is a central listener that delegates particular events out to some intermediary functions, or eats them&lt;a href=&quot;#foot-Sat-Nov-30-122539EST-2013&quot; name=&quot;note-Sat-Nov-30-122539EST-2013&quot;&gt;[5]&lt;/a&gt; as appropriate.&lt;/p&gt;

&lt;p&gt;Keep in mind that the last two speedbumps I hit here probably won&#39;t be felt by most people going in the same direction. Still, I went into this figuring it&#39;d take me a half hour at the outside to implement something workable. It ended up taking me the rest of the day, and will probably cost me another hour or two when I get back in on Monday.&lt;/p&gt;

&lt;p&gt;Such is development sometimes, I suppose.&lt;/p&gt;

&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Sat-Nov-30-122522EST-2013&quot; name=&quot;foot-Sat-Nov-30-122522EST-2013&quot;&gt;[back]&lt;/a&gt; - If you &lt;i&gt;are&lt;/i&gt; going to have other active transformations, using the &lt;code&gt;setAttribute&lt;/code&gt; method would overwrite those, which is why it&#39;s a bad idea.&lt;/p&gt;

&lt;p&gt;2 - &lt;a href=&quot;#note-Sat-Nov-30-122530EST-2013&quot; name=&quot;foot-Sat-Nov-30-122530EST-2013&quot;&gt;[back]&lt;/a&gt; - if you &lt;i&gt;are&lt;/i&gt; doing that, I should point out that the only reason I went the &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt; route here is that both &lt;code&gt;=&amp;gt;&amp;gt;&lt;/code&gt; and &lt;code&gt;=set-attribute&lt;/code&gt; take either an element or a set of elements as their first argument, and I wanted &lt;code&gt;=translate&lt;/code&gt; to do the same. Since you probably won&#39;t have the same situation, you&#39;re likely better off with &lt;code&gt;if&lt;/code&gt;/&lt;code&gt;else&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;3 - &lt;a href=&quot;#note-Sat-Nov-30-122532EST-2013&quot; name=&quot;foot-Sat-Nov-30-122532EST-2013&quot;&gt;[back]&lt;/a&gt; - You wouldn&#39;t want to do this naively either, unless you knew there&#39;d be no other &lt;code&gt;mousemove&lt;/code&gt; events on that top-level element. If you &lt;i&gt;did&lt;/i&gt; have that, you&#39;d want to set up a hook that you could change out rather than messing with event listeners every time you dragged something.&lt;/p&gt;

&lt;p&gt;4 - &lt;a href=&quot;#note-Sat-Nov-30-122536EST-2013&quot; name=&quot;foot-Sat-Nov-30-122536EST-2013&quot;&gt;[back]&lt;/a&gt; - It just occurred to me that you might have no idea what I mean by &quot;hook&quot; in this context. Basically, something like this:

&lt;pre&gt;&lt;span style=&quot;color: #a020f0;&quot;&gt;var&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;mouseMoveHook&lt;/span&gt; = &lt;span style=&quot;color: #008b8b;&quot;&gt;null&lt;/span&gt;;
document.querySelector(&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;body&quot;&lt;/span&gt;).addEventListener(&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;mousemove&quot;&lt;/span&gt;,
  &lt;span style=&quot;color: #a020f0;&quot;&gt;function&lt;/span&gt; (&lt;span style=&quot;color: #a0522d;&quot;&gt;event&lt;/span&gt;){
    &lt;span style=&quot;color: #b22222;&quot;&gt;//&lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;do other stuff
&lt;/span&gt;    &lt;span style=&quot;color: #a020f0;&quot;&gt;if&lt;/span&gt; (mouseMoveHook) { mouseMoveHook(event) };
  });&lt;/pre&gt;

If you have something that looks like that, you can change some of the behavior of your global &lt;code&gt;mousemove&lt;/code&gt; event by assigning a new callback to the &lt;code&gt;mouseMoveHook&lt;/code&gt; variable. I&#39;m sure it&#39;s been used elsewhere, but I learned the term &quot;hook&quot; from Emacs, which provides standard event hooks in a bunch of different situations, and does it more or less this way, modulo some syntactic sugar and multiple hook support.&lt;/p&gt;

&lt;p&gt;5 - &lt;a href=&quot;#note-Sat-Nov-30-122539EST-2013&quot; name=&quot;foot-Sat-Nov-30-122539EST-2013&quot;&gt;[back]&lt;/a&gt; - In the case of the trailing &lt;code&gt;mouseup&lt;/code&gt; event after a drag concludes.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/8832774859243474568/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2013/11/combining-svg-and-html5-is-still-drag.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/8832774859243474568'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/8832774859243474568'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2013/11/combining-svg-and-html5-is-still-drag.html' title='Combining SVG and HTML5 is still a Drag'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-1291354594505085822</id><published>2013-11-26T20:19:00.003-08:00</published><updated>2013-11-26T20:20:29.262-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Flow Based Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="Idea Peeling"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming Environment"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming Interfaces"/><title type='text'>Arbitrary Update 714</title><content type='html'>&lt;p&gt;We&#39;re working on FBP in Common Lisp. You&#39;ve heard that one before.&lt;/p&gt;

&lt;p&gt;Step one was getting a basic system running. In fact, we&#39;ve got two we&#39;re dealing with concurrently&lt;a href=&quot;#foot-Tue-Nov-26-232106EST-2013&quot; name=&quot;note-Tue-Nov-26-232106EST-2013&quot;&gt;[1]&lt;/a&gt;. Both are kind of rickety because I&#39;m still trying to work out what the essential parts of the approach are. One deals with OS threads and the other is built on top of &lt;a href=&quot;http://orthecreedence.github.io/cl-async/&quot;&gt;cl-async&lt;/a&gt;. I&#39;m liking the second one better for now, but am once again reserving judgment until I see how easily they explode.&lt;/p&gt;

&lt;p&gt;Anyhow, that&#39;s price of admission, rather than the finish line. Our ultimate goal is to prove out visual programming in the large, without making anyone throw up about it. I have no idea how that&#39;s going to end up, except that I&#39;ve definitely got a couple of interesting years coming up. In order to get to that ultimate goal, step two is finding or building an Acceptable™© Visual Editor.&lt;/p&gt;

&lt;p&gt;And we can&#39;t find one, so &quot;build&quot; it is.&lt;/p&gt;

&lt;p&gt;What we want, being that we&#39;re Lispers and polyglots to the last, can best be described as &quot;&lt;a href=&quot;https://www.gnu.org/software/emacs/&quot;&gt;Emacs&lt;/a&gt; for Diagrams&quot;. And that doesn&#39;t seem to exist. There&#39;s a &lt;a href=&quot;http://inkscape.org/&quot;&gt;number&lt;/a&gt; of &lt;a href=&quot;http://www.adobe.com/ca/products/illustrator.html?sdid=JRSIH&amp;skwcid=AL!3085!10!2843941197!20355419935&amp;ef_id=UdIbfwAAAaQ4Kybq:20131125030001:s&quot;&gt;general-purpose&lt;/a&gt; vector &lt;a href=&quot;https://code.google.com/p/svg-edit/&quot;&gt;editors&lt;/a&gt; out there at various levels of readiness, but those are more like &quot;MS Word for Diagrams&quot;. There&#39;s a &quot;Sublime for Diagrams&quot; floating around in the form of &lt;a href=&quot;http://www.yworks.com/en/products_yed_about.html&quot;&gt;yEd&lt;/a&gt;, and one piece of fallout from the Russian space program is &lt;a href=&quot;http://drakon-editor.sourceforge.net/&quot;&gt;basically &quot;Notepad++ for Diagrams&quot;&lt;/a&gt;. Microsofts&#39; own &lt;a href=&quot;http://office.microsoft.com/en-ca/visio/&quot;&gt;flowcharting suite&lt;/a&gt; is something like &quot;Eclipse: The Extra Shit Version for Diagrams. Also You Can&#39;t See Our Source Code, Which Is Probably For The Best Because It&#39;s Mostly Garbage You&#39;d Laugh Out Of Your Company In Any Other Context&quot;. Finally, if we want to use &lt;i&gt;Emacs&lt;/i&gt; for diagrams, the only thing even remotely workable seems to be &lt;a href=&quot;http://emacs-fu.blogspot.ca/2009/01/drawing-pictures.html&quot;&gt;&lt;code&gt;artist-mode&lt;/code&gt;&lt;/a&gt;. It&#39;s nice, I guess. Certainly better than prostate cancer. But that&#39;s not quite what we&#39;re looking for.&lt;/p&gt;

&lt;p&gt;The thing we &lt;i&gt;are&lt;/i&gt; looking for needs to be&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;A visual editor&lt;/b&gt;. This needs to be a tool to let humans construct diagrams and related diagrammatic artifacts for a variety of media.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;A diagram editor&lt;/b&gt;. We&#39;re not looking for a general purpose editor. In particular, there are very, very few things we&#39;ll be rotating, nothing we&#39;ll be coloring&lt;a href=&quot;#foot-Tue-Nov-26-232113EST-2013&quot; name=&quot;note-Tue-Nov-26-232113EST-2013&quot;&gt;[2]&lt;/a&gt;, and we only need one font at a fairy small variety of font sizes and weights. We&#39;ll also never be dealing with embedded bitmaps, gradients, brush-strokes, or shapes more complex than rounded rectangles/ellipses. You&#39;d be surprised how much junk that lets you cut out.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Fast&lt;/b&gt;. It shouldn&#39;t take longer to draw a diagram with this thing than it would take to describe it. This means a keyboard-oriented interface with easily re-bindable keys, reasonable performance, reasonable start-up, and no half-baked expert system getting in your way by trying to guess what you&#39;re trying to do.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Scriptable&lt;/b&gt;. It should be possible to &lt;i&gt;simply&lt;/i&gt; and &lt;i&gt;easily&lt;/i&gt; construct sequences of operations to be summoned later. It should be easy to run automated queries and transformations on the programs&#39; output and potentially edit the result in a visual manner. It should be fairly simple to select a particular subset of elements and manipulate them in some way.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Flexible&lt;/b&gt;. We have no idea what the visual formalism we&#39;re finally going to adopt will look like. It might require fine placement of wires and connectors, it might involve different kinds of connections, and it will certainly involve multiple different connections between two nodes&lt;a href=&quot;#foot-Tue-Nov-26-232118EST-2013&quot; name=&quot;note-Tue-Nov-26-232118EST-2013&quot;&gt;[3]&lt;/a&gt;. It also &lt;i&gt;can&#39;t&lt;/i&gt; make any kind of semantic assumptions about what the content we&#39;re editing means, because that might change as we go through the discovery process of what kinds of processes and situations we want to formalize. This also means some sort of proper macro system, an end-user specifiable final/intermediate representation, and source code that we&#39;ll be able to tear apart if we need to.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The various editors I list above are split firmly into two camps. First, there are editors aimed at non-programmer humans for general vector construction. They&#39;re fairly flexible, but because they&#39;re for mouse-pushers, they don&#39;t provide a good intermediate representation for our purposes, don&#39;t particularly care about ease-of-use or keyboard-centricity, and don&#39;t make it particularly easy to script parts of your workflow. In the second camp, there are specialized flow editors aimed at programmers or technical managers, which &lt;i&gt;do&lt;/i&gt; provide a good deal of flexibility on the keyboard binding front, and provide appropriate output, but &lt;i&gt;also&lt;/i&gt; make all kinds of assumptions about what you&#39;re doing, why, and how you should want to go about it.&lt;/p&gt;

&lt;p&gt;If you know of something awesome that I missed, let me know, but for the moment we&#39;re rolling our own. I&#39;ve been working on it for about half a week solid now, and it&#39;s taking shape pretty quickly. I showed off the pre-alpha to some folks at &lt;a href=&quot;https://www.erlang-solutions.com/event/toronto-erlang-factory-lite-2013&quot;&gt;the Erlang conference last week&lt;/a&gt;, and got reactions that didn&#39;t look like outright disgust. Once it takes some usable shape, I&#39;m planning on posting some videos for you, and possibly showing it off a bit to the FBP group.&lt;/p&gt;

&lt;p&gt;I was also going to talk a little bit about fact bases, and the inherent strength of simple models, but I think I&#39;ll leave that for another day. When I get permission to Free this editor, I&#39;ll have quite a bit more to say about that in any case.&lt;/p&gt;

&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Tue-Nov-26-232106EST-2013&quot; name=&quot;foot-Tue-Nov-26-232106EST-2013&quot;&gt;[back]&lt;/a&gt; - Har har, aren&#39;t I droll.&lt;/p&gt;

&lt;p&gt;2 - &lt;a href=&quot;#note-Tue-Nov-26-232113EST-2013&quot; name=&quot;foot-Tue-Nov-26-232113EST-2013&quot;&gt;[back]&lt;/a&gt; - Except for UI purposes, obviously. The various selection/manipulation layers are going to have distinct visual cues that rely on color, but I don&#39;t count these as part of the diagram proper, even though they may be visually associated.&lt;/p&gt;

&lt;p&gt;3 - &lt;a href=&quot;#note-Tue-Nov-26-232118EST-2013&quot; name=&quot;foot-Tue-Nov-26-232118EST-2013&quot;&gt;[back]&lt;/a&gt; - Which incidentally kills any use we might get out of svg-edit&#39;s or Inkscape&#39;s &lt;code&gt;connection&lt;/code&gt; tools. Each of them assume a single connection between two shapes, anchored at each center-point. No idea if said connection can be directional or not, but we&#39;ve already established that it won&#39;t do, so I&#39;m not looking into it.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/1291354594505085822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2013/11/arbitrary-update-714.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/1291354594505085822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/1291354594505085822'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2013/11/arbitrary-update-714.html' title='Arbitrary Update 714'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-102627986525004636</id><published>2013-11-13T13:36:00.003-08:00</published><updated>2013-11-25T08:25:58.933-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Flow Based Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="Media"/><category scheme="http://www.blogger.com/atom/ns#" term="User Group"/><title type='text'>Toronto FBP Group -- Inaugural Meeting Videos</title><content type='html'>&lt;p&gt;I&#39;ve managed to upload the first two videos from the first &lt;a href=&quot;https://bentomiso.com/events/fbp-meetup-nov&quot;&gt;Toronto FBP Group&lt;/a&gt; Meeting to &lt;a href=&quot;https://vimeo.com/user22632094/videos&quot;&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, here&#39;s &lt;a href=&quot;https://vimeo.com/79320781&quot;&gt;Paul Tarvydas giving a brief introduction to FBP&lt;/a&gt;. If you&#39;re a programmer that&#39;s never really heard of Flow Based Programming before, it&#39;s a pretty good start.&lt;/p&gt;

&lt;p&gt;Second, here&#39;s &lt;a href=&quot;https://vimeo.com/79329015&quot;&gt;J. Paul Morrison talking about the history of FBP&lt;/a&gt;. He&#39;s the guy who first discovered the idea, and formalized it while he was working at IBM in the early 1970s, and he talks a bit about what led to the insight. Near the end, he also demos a visual editor he&#39;s currently working on.&lt;/p&gt;

&lt;p&gt;Sadly, because of the Vimeo basic account limitations, the JP Morrison video has a pretty crappy resolution, and &lt;a href=&quot;https://vimeo.com/79814291&quot;&gt;my quick demo talk about a noflo webserver&lt;/a&gt; won&#39;t be uploaded until next week.&lt;/p&gt;

&lt;p&gt;If you really just want the audio and slides, you can get the relevant files right &lt;a href=&quot;http://173.255.226.138/Toronto%20FBP%20Group/meeting-1/&quot;&gt;here&lt;/a&gt;. You can probably get about 60% of the gist from the audio, but all three of us used some relevant visuals in our presentations. In the case of Paul T. and Paul M., a powerpoint presentation, and in my case some noflo code. I&#39;ll try to put up &lt;code&gt;.torrent&lt;/code&gt; links for the HD versions of the videos when I figure out the logistics, and the third video will go up next Tuesday.&lt;/p&gt;

&lt;p&gt;There were no videos from the second meetup&lt;a href=&quot;#foot-Wed-Nov-13-164000EST-2013&quot; name=&quot;note-Wed-Nov-13-164000EST-2013&quot;&gt;[1]&lt;/a&gt;, and there won&#39;t be any from today&lt;a href=&quot;#foot-Wed-Nov-13-164003EST-2013&quot; name=&quot;note-Wed-Nov-13-164003EST-2013&quot;&gt;[2]&lt;/a&gt;. We&#39;re basically trying to figure out how to pay for them; one idea I&#39;m looking into is getting a monthly kickstarter going to let the market decide if there&#39;s enough interest to produce videos for a given month. I&#39;m not sure how much advance notice we&#39;ll need, or how far we can actually plan out talks, but I&#39;ll keep you posted.&lt;/p&gt;

&lt;span class=&quot;edit&quot;&gt;EDIT:
&lt;p&gt;Torrents are now &lt;a href=&quot;http://173.255.226.138/Toronto%20FBP%20Group/meeting-1/&quot;&gt;up along with the audio and presentation materials&lt;/a&gt;. If you do end up downloading these, please seed as long as you can.&lt;/p&gt;
Thu, 14 Nov, 2013&lt;/span&gt;

&lt;span class=&quot;edit&quot;&gt;FURTHER EDIT:
&lt;p&gt;The third video is now up &lt;a href=&quot;https://vimeo.com/79814291&quot;&gt;here&lt;/a&gt;. In it, I briefly introduce &lt;a href=&quot;http://noflojs.org/&quot;&gt;noflo&lt;/a&gt;. If you&#39;d like a half-way decent drinking game, take a shot whenever I say &quot;actually&quot;.&lt;/p&gt;&lt;/span&gt;

&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Wed-Nov-13-164000EST-2013&quot; name=&quot;foot-Wed-Nov-13-164000EST-2013&quot;&gt;[back]&lt;/a&gt; - We basically had a giant whiteboarding session.&lt;/p&gt;

&lt;p&gt;2 - &lt;a href=&quot;#note-Wed-Nov-13-164003EST-2013&quot; name=&quot;foot-Wed-Nov-13-164003EST-2013&quot;&gt;[back]&lt;/a&gt; - We&#39;ve got Paul T. talking about visual compilation, and Jo&#39;sh talking about the &lt;a href=&quot;http://drakon-editor.sourceforge.net/&quot;&gt;Drakon&lt;/a&gt; editor.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/102627986525004636/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2013/11/toronto-fbp-group-inaugural-meeting.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/102627986525004636'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/102627986525004636'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2013/11/toronto-fbp-group-inaugural-meeting.html' title='Toronto FBP Group -- Inaugural Meeting Videos'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-4337965350191858965</id><published>2013-11-10T15:06:00.003-08:00</published><updated>2013-11-12T10:12:58.601-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Bitching"/><category scheme="http://www.blogger.com/atom/ns#" term="General Programming Thoughts"/><category scheme="http://www.blogger.com/atom/ns#" term="Idea Peeling"/><category scheme="http://www.blogger.com/atom/ns#" term="Languages"/><category scheme="http://www.blogger.com/atom/ns#" term="Speculation"/><title type='text'>From The Archives - Popularity</title><content type='html'>&lt;span class=&quot;edit&quot;&gt;EDITOR&#39;S NOTE:

&lt;i&gt;This is a piece I wrote about three years ago, then sat down to copy-edit and polish up today. It was very focused on a few particular, topical anecdotes that my then-co-workers were throwing about. Having read over it equipped with three extra years of hindsight, I&#39;m not sure I&#39;d still be quite as vehement about my opinions as I was here, but don&#39;t disagree on any large points.&lt;/i&gt;

Sun, 10 Nov, 2013&lt;/span&gt;

&lt;p&gt;I&#39;m writing this post because I&#39;ve seen one too many comments of the sort &quot;Well, if PHP is so shitty, then why is it so popular?&quot;. Typically this is the main claim in a rebuttal to &quot;PHP is a shit language&quot;&lt;a href=&quot;#foot-Sun-Nov-10-173728EST-2013&quot; name=&quot;note-Sun-Nov-10-173728EST-2013&quot;&gt;[1]&lt;/a&gt;, and the end result seems to be that a lot of people just sit back and think &quot;Oh yeah, I guess it is popular. It must not be shit, but rugged.&quot; Substitute  &quot;manly&quot;, or &quot;quirky&quot; or similar if you like. As in, yeah, it has flaws, but they&#39;re endearing flaws. Like &lt;a href=&quot;http://us2.php.net/mysql_escape_string&quot;&gt;&lt;code&gt;mysql_escape_string&lt;/code&gt;&lt;/a&gt; being the deprecated precursor to a different function named &lt;a href=&quot;http://php.net/manual/en/function.mysql-real-escape-string.php&quot;&gt;&lt;code&gt;mysql_real_escape_string&lt;/code&gt;&lt;/a&gt; (itself also deprecated). And &lt;a href=&quot;http://bugs.php.net/bug.php?id=12622&quot;&gt;static functions having an odd interpretation of &quot;this&quot;&lt;/a&gt;. And the complete list of &lt;a href=&quot;http://stackoverflow.com/questions/6822446/what-does-php-do-with-deprecated-functions&quot;&gt;deprecated functions&lt;/a&gt; being longer than my average blog post thanks to the fact that they never actually get removed.&lt;/p&gt;

&lt;p&gt;I don&#39;t care that we&#39;ve known how to do better language design for at least thirty years, PHP is Rugged©™, goddamit! And it&#39;s still more popular than whatever properly designed tool it is that you use!&lt;/p&gt;

&lt;h3&gt;How do technologies get popular?&lt;/h3&gt;

&lt;p&gt;This probably won&#39;t turn into an article where I mention Common Lisp&lt;a href=&quot;#foot-Sun-Nov-10-173736EST-2013&quot; name=&quot;note-Sun-Nov-10-173736EST-2013&quot;&gt;[2]&lt;/a&gt;, by the way. The idea of language popularity is almost completely irrelevant to what I&#39;m discussing here; this could be a discussion of any sort of tool and how you&#39;d go about picking one for a particular purpose. The source of popularity is obviously difficult to determine because relatively few things get there, so lets back off a little bit.&lt;/p&gt;

&lt;h3&gt;What does it mean for a tool to be popular?&lt;/h3&gt;

&lt;p&gt;Does it have to solve some specific problem better than other tools? Does it need to be better/cheaper/faster than solving that particular problem by hand? Does it need to be more fun or easier to use? Does it have better marketing/sales/promotions than the competition? Is it the first tool to solve a problem sufficiently well?&lt;/p&gt;

&lt;p&gt;No. To all of the above.&lt;/p&gt;

&lt;p&gt;A tool is popular when enough people have chosen it to perform a given task. Any of the above points &lt;b&gt;contribute to&lt;/b&gt; a tool getting chosen, but for each, you can find a large number of counterexamples. Both tools that lacked it and became popular, and tools that had it but went nowhere. So no single element of that list of points is going to make or break you.&lt;/p&gt;

&lt;p&gt;Lets look at it from the other side instead though.&lt;/p&gt;

&lt;h3&gt;What does it take for someone to choose a given tool?&lt;/h3&gt;

&lt;p&gt;That&#39;s a simpler question, but it should get us the same answer. If &quot;popularity&quot; is &quot;being chosen by enough people&quot; then figuring out &quot;how do most people choose&quot; should tell us &quot;what it means to be popular&quot;.&lt;/p&gt;

&lt;p&gt;A big reason to choose a tool&lt;a href=&quot;#foot-Sun-Nov-10-173739EST-2013&quot; name=&quot;note-Sun-Nov-10-173739EST-2013&quot;&gt;[3]&lt;/a&gt; is that &lt;b&gt;it&#39;ll get you a job&lt;/b&gt;. Again, this has nothing to do with language choice. Lots of people claim &quot;I learned &lt;code&gt;[x]&lt;/code&gt; to get a job&quot;, and &lt;code&gt;[x]&lt;/code&gt; can be &quot;Java&quot; or &quot;C#&quot; with the same probability as &quot;MS Word&quot;, &quot;Photoshop&quot;, &quot;Wordpress&quot;, &quot;typing&quot;, &quot;cooking&quot; or &quot;how to drive a bus&quot;. So one reason people choose is to get a job. Before we drill down to the next level, any other reasons?&lt;/p&gt;

&lt;p&gt;&lt;b&gt;For fun&lt;/b&gt;. I know about as many people who paint/design professionally as those who just do it on the weekend to relax&lt;a href=&quot;#foot-Sun-Nov-10-173742EST-2013&quot; name=&quot;note-Sun-Nov-10-173742EST-2013&quot;&gt;[4]&lt;/a&gt;, and I know plenty of people who just plain like to program. For fun. Like, on &lt;a href=&quot;https://bentomiso.com/events&quot;&gt;nights and weekends&lt;/a&gt;. Granted, not everyone works this way, and not every tool has this effect on people to the same degree&lt;a href=&quot;#foot-Sun-Nov-10-173748EST-2013&quot; name=&quot;note-Sun-Nov-10-173748EST-2013&quot;&gt;[5]&lt;/a&gt;, but it&#39;s still one possible reason.&lt;/p&gt;

&lt;p&gt;Fitness of purpose maybe? Well, not in practice, no. Fitness of purpose is how you pick a specific class of tool. Which is to say, that&#39;s how you know you want a rotary cutter as opposed to a reciprocating saw or a pen and not a sable brush. It still doesn&#39;t tell you that you want a Dremel as opposed to a DeWalt, or a Pilot instead of a Bic&lt;a href=&quot;#foot-Sun-Nov-10-173814EST-2013&quot; name=&quot;note-Sun-Nov-10-173814EST-2013&quot;&gt;[6]&lt;/a&gt;, or ahem, a &lt;a href=&quot;http://www.lua.org/&quot;&gt;Lua&lt;/a&gt; instead of a &lt;a href=&quot;http://ca.php.net/&quot;&gt;PHP&lt;/a&gt;. It&#39;s also not as high a bar as people might think. I try to be objective about it, but from observation, most people tend to treat &quot;fitness of purpose&quot; as &quot;what tool do I currently know how to use that could sort of be put to this use?&quot; rather than &quot;what is the most effective tool for the problem I&#39;m solving?&quot;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Popularity&lt;/b&gt; is the only other big reason I can think of that tools get chosen, but I don&#39;t want to recur just yet, so we&#39;ll leave that one alone. Back up a bit.&lt;/p&gt;

&lt;h2&gt;Tools are popular if they&#39;ll get you a job.&lt;/h2&gt;

&lt;p&gt;When will a tool get you a job? Well, when enough employers start putting it on their job listings. Until that point, it&#39;s not worth learning it &lt;i&gt;just&lt;/i&gt; for that. Tools before that point mostly get adopters that come by because it&#39;s fun for them or the tiny minority that have performed a sufficient comparison and found &lt;i&gt;that&lt;/i&gt; tool to be the best fit for them out of the ones they compared. In other words &lt;i&gt;&quot;I choose tools that will get me jobs&quot;&lt;/i&gt; translates to &lt;i&gt;&quot;I choose tools that employers choose&quot;&lt;/i&gt;.&lt;/p&gt;

&lt;h2&gt;So how do employers choose tools?&lt;/h2&gt;

&lt;p&gt;Well, here, I can actually share some small amount of real-world data. Anecdotal, so take it with a grain of salt, but enough to form a theory. If anyone wants to try being the experimentalist on this one, be my guest. If you did it well enough, I&#39;m sure it&#39;d be publishable.&lt;/p&gt;

&lt;p&gt;There are a few major points that impact on what an organization does in terms of technical tool choice&lt;a href=&quot;#foot-Sun-Nov-10-173817EST-2013&quot; name=&quot;note-Sun-Nov-10-173817EST-2013&quot;&gt;[7]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The biggest one is &lt;i&gt;&quot;We&#39;ll keep using what we&#39;re using&quot;&lt;/i&gt;. Which is to say, if the previous project turned out to be successful, there will be a big push to use the same tools on the next one. Interestingly, this happens even if the success of the last project had everything to do with the team pulling constant overtime, and nothing at all to do with tool choice. The tools can be actively detrimental to the goal and &lt;i&gt;still&lt;/i&gt; reap a rep-boost if the project succeeds. This doesn&#39;t really answer anything. How does a company choose their tools on the first project?&lt;/p&gt;

&lt;p&gt;A few different ways. The tool choice for Project Number 1™© is contingent on&lt;a href=&quot;#foot-Sun-Nov-10-173820EST-2013&quot; name=&quot;note-Sun-Nov-10-173820EST-2013&quot;&gt;[8]&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;What do our developers know how to use?&lt;/li&gt;
  &lt;li&gt;What do our vendors use?&lt;/li&gt;
  &lt;li&gt;What do our clients want us to use?&lt;/li&gt;
  &lt;li&gt;What&#39;s the industry standard?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first one at least has some expert input, but works oddly. You don&#39;t get choice bias towards the &quot;best&quot;&lt;a href=&quot;#foot-Sun-Nov-10-173836EST-2013&quot; name=&quot;note-Sun-Nov-10-173836EST-2013&quot;&gt;[9]&lt;/a&gt; tool, but rather the most popular. If Bleeb is &quot;better&quot; than Blub, but only two people on a team of ten know Bleeb whereas everyone knows Blub, then the team uses Blub&lt;a href=&quot;#foot-Sun-Nov-10-173841EST-2013&quot; name=&quot;note-Sun-Nov-10-173841EST-2013&quot;&gt;[10]&lt;/a&gt;. In other words, no help there; this criteria will get you the popular language without requiring any level of quality or rigor in its design principles.&lt;/p&gt;

&lt;p&gt;The second one is just plain odd, and before sitting back and observing, I would have sworn that it would be a really weak reason to use a tool. Companies seem to not care though; if a given preferred vendor uses tool &lt;code&gt;[x]&lt;/code&gt; for task &lt;code&gt;[y]&lt;/code&gt;, then the company tends to use tool &lt;code&gt;[x]&lt;/code&gt;, even if it&#39;s ridiculously awkward to &lt;i&gt;actually&lt;/i&gt; use. The vendor is also a company, so they use this same process for picking their tools, so substitute that back once we&#39;re done.&lt;/p&gt;

&lt;p&gt;The third one is obvious, I hope, but it also boils down to &quot;popularity&quot; because very few clients know the problem space. Typically, they listen to the first/best sales people that talk to them. They&#39;re a force though; if your target client wants it on MSSQL and .NET, then it&#39;ll either be &lt;i&gt;that&lt;/i&gt; or it won&#39;t &lt;i&gt;be&lt;/i&gt;.&lt;/p&gt;

&lt;p&gt;The fourth one is the previous answer on a macro scale; &lt;i&gt;&quot;We&#39;ll keep using what we&#39;re using (as an industry)&quot;&lt;/i&gt;. In other words, if there were lots of successful companies using tool &lt;code&gt;[x]&lt;/code&gt;, we&#39;ll use it too&lt;a href=&quot;#foot-Sun-Nov-10-173852EST-2013&quot; name=&quot;note-Sun-Nov-10-173852EST-2013&quot;&gt;[11]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Now&lt;/i&gt;, we need to go deeper&lt;a href=&quot;#foot-Sun-Nov-10-173855EST-2013&quot; name=&quot;note-Sun-Nov-10-173855EST-2013&quot;&gt;[12]&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;How does the first company in an industry pick their tools?&lt;/h3&gt;

&lt;p&gt;Regardless of any other decision factors, the answer is almost by definition &quot;before they really know what problems those tools will have to solve&quot;, and I&#39;ve already discussed that one &lt;a href=&quot;http://langnostic.blogspot.ca/2012/02/self-titled.html&quot;&gt;pretty thoroughly&lt;/a&gt;. There are no clients, so they can&#39;t pick that way, there are no other companies or vendors so there is no industry standard. They might look at what similar industries do. Would they use the best possible tool for the job though? Well, no. They&#39;re likely to go the &lt;i&gt;&quot;What do our developers know how to use?&quot;&lt;/i&gt; route, which we&#39;ve already discussed above.&lt;/p&gt;

&lt;p&gt;The big reasons &lt;b&gt;teams&lt;/b&gt;&lt;a href=&quot;#foot-Sun-Nov-10-173906EST-2013&quot; name=&quot;note-Sun-Nov-10-173906EST-2013&quot;&gt;[13]&lt;/a&gt; pick a given technology include&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;how easy is it to hire people that know how to use this? (easier the better)&lt;/li&gt;
  &lt;li&gt;do we have existing code that we&#39;ll need to interface with? (if so, weigh whatever we used on that project favorably)&lt;/li&gt;
  &lt;li&gt;have we used any technologies in the past for similar purposes to what we&#39;re doing here? (if so, weigh those favorably)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and the big one&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;if I choose this, and anything blows up, will I still be able to make the case to non-technical humans that it was the right choice? (if not, weigh it very unfavorably)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;1, 2 and 3 mean that the more popular the language is, the more chance it has of getting entrenched&lt;a href=&quot;#foot-Sun-Nov-10-173915EST-2013&quot; name=&quot;note-Sun-Nov-10-173915EST-2013&quot;&gt;[14]&lt;/a&gt;. 4 means the same, but this time &quot;popular&quot; means overall, not just within the tech community. A non-tech has heard the name &quot;PHP&quot; before, enough times to associate it with &quot;the web&quot; and &quot;Facebook&quot; and &quot;Wordpress&quot;, but probably hasn&#39;t looked into it closely enough to catch complaints from developers&lt;a href=&quot;#foot-Sun-Nov-10-173918EST-2013&quot; name=&quot;note-Sun-Nov-10-173918EST-2013&quot;&gt;[15]&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The end result is that, in a sufficiently large company, it&#39;s safer to use a popular tool that&#39;s poor in the technical sense than it is to use an excellent tool no one&#39;s heard of. And that&#39;s &lt;i&gt;also&lt;/i&gt; been &lt;a href=&quot;http://paulgraham.com/avg.html&quot;&gt;discussed thoroughly&lt;/a&gt;, and &lt;a href=&quot;http://www.joelonsoftware.com/items/2006/09/01.html&quot;&gt;this time&lt;/a&gt; it wasn&#39;t even by me. The decision is made purely on the basis of popularity once again.&lt;/p&gt;

&lt;h3&gt;Shit&lt;/h3&gt;

&lt;p&gt;We just bottomed out our recursion. Just in case you haven&#39;t been keeping score, literally every single level at which a tool can be selected is likely to be filled by the most popular tool in some context, and this popularity never requires, therefore never implies, &lt;i&gt;anything other than popularity&lt;/i&gt;. One more time: &lt;b&gt;at no point in the process of selecting a toolkit do most choosers even try to see whether it&#39;s shit or not.&lt;/b&gt; So I don&#39;t care how popular your steaming pile of imperative, counter-intuitive security-exploits-waiting-to-happen is; it&#39;s still shit.&lt;/p&gt;

&lt;p&gt;Don&#39;t let me stop you from eating it, but I remember what it tastes like so I won&#39;t be joining you. Or shaking your hand afterwards.&lt;/p&gt;

&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Sun-Nov-10-173728EST-2013&quot; name=&quot;foot-Sun-Nov-10-173728EST-2013&quot;&gt;[back]&lt;/a&gt; - Which I happen to agree with, actually. If you&#39;re looking for details on what language&lt;b&gt;s&lt;/b&gt;(Spoiler warning) I&#39;d recommend learning, you&#39;re better off reading &lt;a href=&quot;http://langnostic.blogspot.ca/2013/03/what-programming-language-should-i-learn.html&quot;&gt;this&lt;/a&gt; instead.&lt;/p&gt;

&lt;p&gt;2 - &lt;a href=&quot;#note-Sun-Nov-10-173736EST-2013&quot; name=&quot;foot-Sun-Nov-10-173736EST-2013&quot;&gt;[back]&lt;/a&gt; - Except for that.&lt;/p&gt;
&lt;p&gt;3 - &lt;a href=&quot;#note-Sun-Nov-10-173739EST-2013&quot; name=&quot;foot-Sun-Nov-10-173739EST-2013&quot;&gt;[back]&lt;/a&gt; - Generally among the people I know at least, no judgment here.&lt;/p&gt;

&lt;p&gt;4 - &lt;a href=&quot;#note-Sun-Nov-10-173742EST-2013&quot; name=&quot;foot-Sun-Nov-10-173742EST-2013&quot;&gt;[back]&lt;/a&gt; - That&#39;s what I get for going to design school.&lt;/p&gt;

&lt;p&gt;5 - &lt;a href=&quot;#note-Sun-Nov-10-173748EST-2013&quot; name=&quot;foot-Sun-Nov-10-173748EST-2013&quot;&gt;[back]&lt;/a&gt; - Point of fact, only one person I know drives a bus for fun. It&#39;s been his obsession to work for the TTC since grade 8. I haven&#39;t heard from him in a while, but I still remember his room being full of papercraft Orion 3s, and I&#39;m pretty sure he spent every internship opportunity he had on some streetcar route or another.&lt;/p&gt;

&lt;p&gt;6 - &lt;a href=&quot;#note-Sun-Nov-10-173814EST-2013&quot; name=&quot;foot-Sun-Nov-10-173814EST-2013&quot;&gt;[back]&lt;/a&gt; - The pen fanciers among you are probably ready to tell me that these are the worst possible examples; they&#39;re just the most popular common brand pens, not the really good stuff, where quality can make a difference. Really, I should have used &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt;. You can go now, if you ponder that point hard enough, you pretty much got the gist of the article.&lt;/p&gt;

&lt;p&gt;7 - &lt;a href=&quot;#note-Sun-Nov-10-173817EST-2013&quot; name=&quot;foot-Sun-Nov-10-173817EST-2013&quot;&gt;[back]&lt;/a&gt; - I&#39;m reigning it in a bit to software tools because that&#39;s what I have experience with, but this still seems like it might be a general trend; again, experimentalists welcome.&lt;/p&gt;

&lt;p&gt;8 - &lt;a href=&quot;#note-Sun-Nov-10-173820EST-2013&quot; name=&quot;foot-Sun-Nov-10-173820EST-2013&quot;&gt;[back]&lt;/a&gt; - In varying order, in my experience, but always on these things.&lt;/p&gt;

&lt;p&gt;9 - &lt;a href=&quot;#note-Sun-Nov-10-173836EST-2013&quot; name=&quot;foot-Sun-Nov-10-173836EST-2013&quot;&gt;[back]&lt;/a&gt; - Which I&#39;m still quoting. In a book, that&#39;s called &quot;foreshadowing&quot;. In a game or movie, it&#39;s called &quot;setting up the sequel&quot;.&lt;/p&gt;

&lt;p&gt;10 - &lt;a href=&quot;#note-Sun-Nov-10-173841EST-2013&quot; name=&quot;foot-Sun-Nov-10-173841EST-2013&quot;&gt;[back]&lt;/a&gt; - And you get a varying amount of childish name-calling and dismissiveness towards Bleeb.&lt;/p&gt;

&lt;p&gt;11 - &lt;a href=&quot;#note-Sun-Nov-10-173852EST-2013&quot; name=&quot;foot-Sun-Nov-10-173852EST-2013&quot;&gt;[back]&lt;/a&gt; - Again, disregarding whether the tool had any effect at all on success.&lt;/p&gt;

&lt;p&gt;12 - &lt;a href=&quot;#note-Sun-Nov-10-173855EST-2013&quot; name=&quot;foot-Sun-Nov-10-173855EST-2013&quot;&gt;[back]&lt;/a&gt; - And at this point, all bets are off, I&#39;m just theorizing, because I haven&#39;t observed the decision making process in an industry-defining company. That would be an interesting research project though, let me know if you&#39;ve got one lined up.&lt;/p&gt;

&lt;p&gt;13 - &lt;a href=&quot;#note-Sun-Nov-10-173906EST-2013&quot; name=&quot;foot-Sun-Nov-10-173906EST-2013&quot;&gt;[back]&lt;/a&gt; - Not individual developers, but groups of corporate developers complete with leaders, technical or not, who are ultimately responsible to non-tech people further up the hierarchy.&lt;/p&gt;

&lt;p&gt;14 - &lt;a href=&quot;#note-Sun-Nov-10-173915EST-2013&quot; name=&quot;foot-Sun-Nov-10-173915EST-2013&quot;&gt;[back]&lt;/a&gt; - And note that both points are completely unrelated to how &quot;good&quot; a language is, and entirely dependent on how popular it is.&lt;/p&gt;

&lt;p&gt;15 - &lt;a href=&quot;#note-Sun-Nov-10-173918EST-2013&quot; name=&quot;foot-Sun-Nov-10-173918EST-2013&quot;&gt;[back]&lt;/a&gt; - Or to determine whether there&#39;s a lot of overlap between &quot;good developers&quot; and &quot;developers who complain vocally about PHP&quot;.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/4337965350191858965/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2013/11/from-archives-popularity.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/4337965350191858965'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/4337965350191858965'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2013/11/from-archives-popularity.html' title='From The Archives - Popularity'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-4660538709510374429</id><published>2013-11-10T08:34:00.000-08:00</published><updated>2013-11-10T08:35:13.330-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="General Programming Thoughts"/><category scheme="http://www.blogger.com/atom/ns#" term="Idea Peeling"/><category scheme="http://www.blogger.com/atom/ns#" term="Speculation"/><title type='text'>Briefly, Custom Server Redux</title><content type='html'>&lt;p&gt;So you already know I&#39;m &lt;a href=&quot;http://langnostic.blogspot.ca/2013/10/deal-journal-interlude-two-being.html&quot;&gt;building a custom HTTP server for Deal&lt;/a&gt;. A question has arisen in my mind: how customized do I want it?&lt;/p&gt;

&lt;p&gt;My initial assumption was that I&#39;d just make it the usual general purpose HTTP server, with a few pieces focused on my end goal, but now that I&#39;m waist deep in the guts of this thing, it occurs that I could take it further if I wanted to. For my current purposes, a relatively small subset of HTTP would do just fine. Here are the points I&#39;ve noticed:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Deal never runs into the situation where both a GET and a POST parameter have the same name. As a result, I can do the Hunchentoot-standard thing and mangle parameters so that &lt;code&gt;get-params&lt;/code&gt; and &lt;code&gt;post-params&lt;/code&gt; are actually kept in the same associative structure. That simplifies the structure of both &lt;code&gt;request&lt;/code&gt; objects and of handler functions, at the cost of differentiating between parameter types.&lt;/li&gt;
  &lt;li&gt;Because there&#39;s never an ambiguity between GET and POST parameters, I don&#39;t even really need to differentiate between GET and POST &lt;i&gt;requests&lt;/i&gt;. That&#39;ll simplify the class tree of incoming requests. Specifically, it&#39;ll cap its depth at 1.&lt;/li&gt;
  &lt;li&gt;There are only two handlers that allow session-less requests, the rest require that the requester have a session&lt;a href=&quot;#foot-Sat-Nov-09-184009EST-2013&quot; name=&quot;note-Sat-Nov-09-184009EST-2013&quot;&gt;[1]&lt;/a&gt;, so what I could do is just make each request start up a session if a valid session token isn&#39;t passed in. That&#39;ll occasionally burn a few milliseconds of extra work&lt;a href=&quot;#foot-Sat-Nov-09-184013EST-2013&quot; name=&quot;note-Sat-Nov-09-184013EST-2013&quot;&gt;[2]&lt;/a&gt;, but it&#39;ll remove the need to assert session presence at the application level.&lt;/li&gt;
  &lt;li&gt;Because Deal is already targeting recent browsers&lt;a href=&quot;#foot-Sat-Nov-09-184016EST-2013&quot; name=&quot;note-Sat-Nov-09-184016EST-2013&quot;&gt;[3]&lt;/a&gt;, there&#39;s no need to support any older version of HTTP.&lt;/li&gt;
  &lt;li&gt;Finally, because there&#39;s &lt;i&gt;only one&lt;/i&gt; handler that&#39;s going to need to handle extended connections, and the rest will always return immediately, I can more or less ignore request headers. In particular, I never care about &lt;code&gt;Connection&lt;/code&gt;&lt;a href=&quot;#foot-Sat-Nov-09-184019EST-2013&quot; name=&quot;note-Sat-Nov-09-184019EST-2013&quot;&gt;[4]&lt;/a&gt;, &lt;code&gt;Accept&lt;/code&gt;&lt;a href=&quot;#foot-Sat-Nov-09-184022EST-2013&quot; name=&quot;note-Sat-Nov-09-184022EST-2013&quot;&gt;[5]&lt;/a&gt; or &lt;code&gt;Cache-Control&lt;/code&gt;&lt;a href=&quot;#foot-Sat-Nov-09-184025EST-2013&quot; name=&quot;note-Sat-Nov-09-184025EST-2013&quot;&gt;[6]&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Acting on each of these assumptions is going to narrow the usefulness of the server, but also significantly simplify it. The optimum is eluding me, though I suspect it might be &quot;as simple as possible&quot; given my end goal for this particular project. Interestingly, even if I decide to do the simple thing for each of the choices outlined above, the end result will still probably be a useful general-purpose game server.&lt;/p&gt;

&lt;p&gt;The only really funny part is that, now that I&#39;ve thought it through, implementing this system as a websocket server&lt;a href=&quot;#foot-Sun-Nov-10-113904EST-2013&quot; name=&quot;note-Sun-Nov-10-113904EST-2013&quot;&gt;[7]&lt;/a&gt; seems like it would yield an even simpler architecture. I&#39;ll save that one for later though. Step one: simple SSE+session based engine, make sure it works, &lt;i&gt;then&lt;/i&gt; rip out its guts again and see what the other way looks like.&lt;/p&gt;

&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Sat-Nov-09-184009EST-2013&quot; name=&quot;foot-Sat-Nov-09-184009EST-2013&quot;&gt;[back]&lt;/a&gt; - And most of &lt;i&gt;those&lt;/i&gt; require that the session be associated with a particular, already-instantiated game table, but optimizing for that seems like it would be going too far.&lt;/p&gt;

&lt;p&gt;2 - &lt;a href=&quot;#note-Sat-Nov-09-184013EST-2013&quot; name=&quot;foot-Sat-Nov-09-184013EST-2013&quot;&gt;[back]&lt;/a&gt; - When someone who &lt;i&gt;just&lt;/i&gt; wants to watch rather than play first checks out a table.&lt;/p&gt;
&lt;p&gt;3 - &lt;a href=&quot;#note-Sat-Nov-09-184016EST-2013&quot; name=&quot;foot-Sat-Nov-09-184016EST-2013&quot;&gt;[back]&lt;/a&gt; - We&#39;re using quite a few features of HTML5 to make the whole thing playable.&lt;/p&gt;

&lt;p&gt;4 - &lt;a href=&quot;#note-Sat-Nov-09-184019EST-2013&quot; name=&quot;foot-Sat-Nov-09-184019EST-2013&quot;&gt;[back]&lt;/a&gt; - That one that I mentioned will be assumed &lt;code&gt;keep-alive&lt;/code&gt;, while the rest assume the reverse.&lt;/p&gt;

&lt;p&gt;5 - &lt;a href=&quot;#note-Sat-Nov-09-184022EST-2013&quot; name=&quot;foot-Sat-Nov-09-184022EST-2013&quot;&gt;[back]&lt;/a&gt; - You&#39;re expecting &lt;code&gt;text/html&lt;/code&gt; on the main request, &lt;code&gt;text/event-stream&lt;/code&gt; on the subscription and &lt;code&gt;application/json&lt;/code&gt; on the rest. If you can&#39;t handle those, you won&#39;t be able to play in any case.&lt;/p&gt;
&lt;p&gt;6 - &lt;a href=&quot;#note-Sat-Nov-09-184025EST-2013&quot; name=&quot;foot-Sat-Nov-09-184025EST-2013&quot;&gt;[back]&lt;/a&gt; - Everything other than the static file handlers always re-generates content; the static handlers don&#39;t need to change unless the files themselves have actually changed.&lt;/p&gt;

&lt;p&gt;7 - &lt;a href=&quot;#note-Sun-Nov-10-113904EST-2013&quot; name=&quot;foot-Sun-Nov-10-113904EST-2013&quot;&gt;[back]&lt;/a&gt; - Which multiple people have already recommended to me, so I&#39;m not taking credit for that particular insight.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/4660538709510374429/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2013/11/breifly-custom-server-redux.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/4660538709510374429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/4660538709510374429'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2013/11/breifly-custom-server-redux.html' title='Briefly, Custom Server Redux'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-8667330148080472494</id><published>2013-11-06T13:34:00.001-08:00</published><updated>2013-11-15T07:55:19.683-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Common Lisp"/><category scheme="http://www.blogger.com/atom/ns#" term="Flow Based Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="snippets"/><title type='text'>FBP in Common Lisp</title><content type='html'>&lt;p&gt;Guess what!&lt;/p&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;I can finally tell you what I&#39;m doing at work. A friend has suggested that I just not mention that there are things I still can&#39;t talk about, so I won&#39;t. In any case, all the interesting stuff is fair game. Apparently, I&#39;m allowed to talk about it in much greater detail than I can write about it because a persistent record is still frightening to some humans. Progress, I guess.&lt;/p&gt;

&lt;p&gt;We&#39;ve been doing &lt;a href=&quot;http://en.wikipedia.org/wiki/Flow-based_programming&quot;&gt;Flow Based Programming&lt;/a&gt; in &lt;a href=&quot;http://www.gigamonkeys.com/book/&quot;&gt;Common Lisp&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Damn&lt;/b&gt; it feels good to finally get that off my chest. I have no idea how &lt;a href=&quot;http://steve-yegge.blogspot.ca/&quot;&gt;Yegge&lt;/a&gt; stopped blogging. I&#39;m guessing he hasn&#39;t, but rather just stopped publishing the results. I&#39;ve been writing about one thing for the past little while, and the number of ideas I &lt;i&gt;need&lt;/i&gt; to discuss with the &lt;a href=&quot;http://en.wikipedia.org/wiki/Rubber_duck_debugging&quot;&gt;rubber duck&lt;/a&gt; at some point is staggering. If my output rate were zero, I would probably have a pretty tenuous grip on my sanity.&lt;/p&gt;

&lt;p&gt;This is heading off topic. Once more, &lt;i&gt;with feeling&lt;/i&gt;&lt;/p&gt;

&lt;h3&gt;Flow Based Programming in Common Lisp&lt;/h3&gt;

&lt;p&gt;I&#39;m not sure what I think about it yet. Lets just be clear about that up-front. You&#39;ll find plenty of FBP True Believers on the appropriate &lt;a href=&quot;https://groups.google.com/forum/#!forum/flow-based-programming&quot;&gt;Google group&lt;/a&gt;&lt;a href=&quot;#foot-Wed-Nov-06-161759EST-2013&quot; name=&quot;note-Wed-Nov-06-161759EST-2013&quot;&gt;[1]&lt;/a&gt;, but I am not one of those. The fact that I&#39;m willing to throw a couple years behind the idea implies curiosity, nothing more.&lt;/p&gt;

&lt;p&gt;A matter quite apart from the underlying structure is our implementation of it, and I &lt;b&gt;am&lt;/b&gt; certain that it&#39;s over-complicated. Granted, based on all the others I&#39;ve seen, ours is the &lt;i&gt;least&lt;/i&gt; over-complicated, but still. That&#39;s something I&#39;ll aim to fix, with a personal project as a last resort, if I can&#39;t convince anyone else about it. But I digress. Again.&lt;/p&gt;

&lt;p&gt;Here&#39;s why I&#39;m curious. This is what a basic web server looks like in flow-based terms:&lt;/p&gt;

&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAkArhfl9xUEDxfPZ3MNCZR2U_vNBBXKJq5kQcfMXoniPXgJimUGO6cPEuzCB8PxhRw1mzcO6jRrE2pNIKnWY2tSmrW0imkOgXyBhZrbAoO3SyFvgKDhtmkmHgd2ECAesd57EQDPc1CMTi/s1600/server-1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAkArhfl9xUEDxfPZ3MNCZR2U_vNBBXKJq5kQcfMXoniPXgJimUGO6cPEuzCB8PxhRw1mzcO6jRrE2pNIKnWY2tSmrW0imkOgXyBhZrbAoO3SyFvgKDhtmkmHgd2ECAesd57EQDPc1CMTi/s320/server-1.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;And here&#39;s what it looks like once you add SSE capability to it:&lt;/p&gt;

&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaXfBpr6GfRKksEpvoS0q4HnluzUab7_Rbb21J_RbR-WXSXy8FySCSDmhe67IEDxsPCsebH1MkUVSgqFXWtreEgI6agB5MB0mHDGElmlWfdCgOhCDui-whQJ5jBZu_rnMP3adobA0hs49H/s1600/server-2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgaXfBpr6GfRKksEpvoS0q4HnluzUab7_Rbb21J_RbR-WXSXy8FySCSDmhe67IEDxsPCsebH1MkUVSgqFXWtreEgI6agB5MB0mHDGElmlWfdCgOhCDui-whQJ5jBZu_rnMP3adobA0hs49H/s320/server-2.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;and finally, here&#39;s what it looks like when we add sessions into the mix&lt;/p&gt;

&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEih129YUWFyH24ybj7UOCntp2Xl4t0aawzuRB9Q6PV8lCtBYveruo0Zr4SNq9sIVbSpQmDJT45zeL0mAjMoCwIfCm700CFxyVw615mlv4D7DkUvP2ZhcDZPBVUqdalqcYnCgwungyZI9ZYj/s1600/server-3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEih129YUWFyH24ybj7UOCntp2Xl4t0aawzuRB9Q6PV8lCtBYveruo0Zr4SNq9sIVbSpQmDJT45zeL0mAjMoCwIfCm700CFxyVw615mlv4D7DkUvP2ZhcDZPBVUqdalqcYnCgwungyZI9ZYj/s320/server-3.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;The above is by far the most useful set of images I&#39;ve got for understanding what&#39;s actually going on behind the scenes of a page-view. I&#39;ve worked through the principles in multiple languages and spent quite a bit of time thinking about it, but until I sat down to draw it out, it didn&#39;t feel like I &lt;i&gt;really&lt;/i&gt; understood what needed to be done. You probably don&#39;t know the same languages I do, but the above is still likely intelligible to you. So that&#39;s why I&#39;m curious.&lt;/p&gt;

&lt;h3&gt;Flow Based Programming vs. Functional Programming&lt;/h3&gt;

&lt;p&gt;Before I go, I want to tackle this, because several people I&#39;ve talked to have gotten tripped up in the comparison. Including me. I ended up deleting a few lines from this post that said&lt;/p&gt;

&lt;blockquote&gt;
  The underlying problem for my lack of &quot;wow&quot; reaction might actually be my usual languages. I&#39;m &lt;i&gt;used&lt;/i&gt; to thinking about streams moving between inter-connected, lazy processors. That&#39;s the main way I conceptualize Haskell. In fact, if you squint just a bit, it&#39;s the way you can conceptualize most functional programs, pure or not. &lt;span class=&quot;sig&quot;&gt;-Inaimathi&lt;/span&gt;
&lt;/blockquote&gt;

&lt;p&gt;The difference is that functional programming focuses on partial conceptual separation, whereas FBP takes the isolation concept a few steps further by enforcing &lt;i&gt;complete&lt;/i&gt; conceptual separation as well as complete &lt;i&gt;temporal&lt;/i&gt; separation. Here&#39;s the accompanying thought experiment, just to clarify what I mean by that.&lt;/p&gt;

&lt;p&gt;Suppose you were writing in a functional language and wrote the following:&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #a020f0;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;foo&lt;/span&gt;():
   ...
   bar(&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;something&quot;&lt;/span&gt;)
   baz(&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;something else&quot;&lt;/span&gt;)

&lt;span style=&quot;color: #a020f0;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;bar&lt;/span&gt;(arg):
   ...
   doStuff()

&lt;span style=&quot;color: #a020f0;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #0000ff;&quot;&gt;baz&lt;/span&gt;(arg):
   ...
   doOtherStuff()&lt;/pre&gt;

&lt;p&gt;Firstly, notice that, while the functions are conceptually separate units&lt;a href=&quot;#foot-Wed-Nov-06-161805EST-2013&quot; name=&quot;note-Wed-Nov-06-161805EST-2013&quot;&gt;[2]&lt;/a&gt;, &lt;code&gt;foo&lt;/code&gt; still has to know about &lt;code&gt;bar&lt;/code&gt; and &lt;code&gt;baz&lt;/code&gt;. That prevents total isolation. Yes, you can re-define &lt;code&gt;bar&lt;/code&gt; and &lt;code&gt;baz&lt;/code&gt; in-flight if your language is dynamic enough, but you need to have them both defined and you need to have them named &lt;code&gt;bar&lt;/code&gt; and &lt;code&gt;baz&lt;/code&gt; before &lt;code&gt;foo&lt;/code&gt; can actually run.&lt;/p&gt;

&lt;p&gt;Secondly, note that what&#39;s happening there is most likely a bunch of synchronous work. That is, when &lt;code&gt;foo&lt;/code&gt; calls &lt;code&gt;bar&lt;/code&gt; and &lt;code&gt;baz&lt;/code&gt;, both calls complete and then &lt;code&gt;foo&lt;/code&gt; returns the return value of &lt;code&gt;baz&lt;/code&gt;&lt;a href=&quot;#foot-Wed-Nov-06-161811EST-2013&quot; name=&quot;note-Wed-Nov-06-161811EST-2013&quot;&gt;[3]&lt;/a&gt;. If you wrote the equivalent in a &lt;i&gt;pure&lt;/i&gt;-functional language, the actual work may happen in a different order than you see it written out, subject to what the compiler can prove about the behavior of the functions involved, but &lt;code&gt;bar&lt;/code&gt; and &lt;code&gt;baz&lt;/code&gt; will still complete before &lt;code&gt;foo&lt;/code&gt; does. If they didn&#39;t, you&#39;d get some unexpected behavior in any callers of &lt;code&gt;foo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, lets take a look at the apparently equivalent, Lisp-flavoured, FBP-style program.&lt;/p&gt;

&lt;pre&gt;(&lt;span style=&quot;color: #a020f0;&quot;&gt;define-part&lt;/span&gt; foo ()
  ...
  (out! &lt;span style=&quot;color: #7a378b;&quot;&gt;:out&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;something&quot;&lt;/span&gt;)
  (out! &lt;span style=&quot;color: #7a378b;&quot;&gt;:log&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;something else&quot;&lt;/span&gt;))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;define-part&lt;/span&gt; bar ()
  ...
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;do-stuff&lt;/span&gt;))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;define-part&lt;/span&gt; baz ()
  (&lt;span style=&quot;color: #a020f0;&quot;&gt;do-other-stuff&lt;/span&gt;))

(&lt;span style=&quot;color: #a020f0;&quot;&gt;define-container&lt;/span&gt; box 
    (&lt;span style=&quot;color: #7a378b;&quot;&gt;:foo&lt;/span&gt; (foo) &lt;span style=&quot;color: #7a378b;&quot;&gt;:bar&lt;/span&gt; (bar) &lt;span style=&quot;color: #7a378b;&quot;&gt;:baz&lt;/span&gt; (baz))
  ((&lt;span style=&quot;color: #7a378b;&quot;&gt;:foo&lt;/span&gt; &lt;span style=&quot;color: #7a378b;&quot;&gt;:out&lt;/span&gt;) -&amp;gt; (&lt;span style=&quot;color: #7a378b;&quot;&gt;:bar&lt;/span&gt; &lt;span style=&quot;color: #7a378b;&quot;&gt;:in&lt;/span&gt;))
  ((&lt;span style=&quot;color: #7a378b;&quot;&gt;:foo&lt;/span&gt; &lt;span style=&quot;color: #7a378b;&quot;&gt;:log&lt;/span&gt;) -&amp;gt; (&lt;span style=&quot;color: #7a378b;&quot;&gt;:baz&lt;/span&gt; &lt;span style=&quot;color: #7a378b;&quot;&gt;:in&lt;/span&gt;))))&lt;/pre&gt;

&lt;p&gt;First, notice that &lt;code&gt;foo&lt;/code&gt; doesn&#39;t know anything about &lt;code&gt;bar&lt;/code&gt; or &lt;code&gt;baz&lt;/code&gt;, or anything about the &lt;i&gt;existence&lt;/i&gt; of either. At some point during its execution, it outputs two messages to some implementation-dependent output structure, but critically &lt;i&gt;&lt;code&gt;foo&lt;/code&gt; itself is not responsible for delivering those outputs to their consumers&lt;/i&gt;. That allows for total part-agnosticism; you really can shuffle parts around with pin-equivalent parts and have the result work. In functional or actors-based systems, you can &lt;i&gt;almost&lt;/i&gt; do the same; the exception is that since each sender/caller has to name targets in some way, you need to change small chunks of code in places where functions/actors interoperate.&lt;/p&gt;

&lt;p&gt;Second, note that there&#39;s nothing in this system about the timing of &lt;code&gt;bar&lt;/code&gt; and &lt;code&gt;baz&lt;/code&gt;. This omission includes the fact that both, either or neither may run before &lt;code&gt;foo&lt;/code&gt; completes. In this model of the world, if &lt;code&gt;bar&lt;/code&gt; takes a while to run, neither &lt;code&gt;baz&lt;/code&gt; nor &lt;code&gt;foo&lt;/code&gt;, nor any of their callers are prevented from further operation. The second critical difference is, essentially, that asynchronous operation is the norm.&lt;/p&gt;

&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Wed-Nov-06-161759EST-2013&quot; name=&quot;foot-Wed-Nov-06-161759EST-2013&quot;&gt;[back]&lt;/a&gt; - Currently mostly Javascripters thanks to the hype surrounding &lt;a href=&quot;http://noflojs.org/&quot;&gt;noflo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;2 - &lt;a href=&quot;#note-Wed-Nov-06-161805EST-2013&quot; name=&quot;foot-Wed-Nov-06-161805EST-2013&quot;&gt;[back]&lt;/a&gt; - Assuming the programmer hasn&#39;t done something &quot;clever&quot; with global variables, &lt;code&gt;goto&lt;/code&gt;s or &lt;code&gt;comefrom&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;3 - &lt;a href=&quot;#note-Wed-Nov-06-161811EST-2013&quot; name=&quot;foot-Wed-Nov-06-161811EST-2013&quot;&gt;[back]&lt;/a&gt; - which happens to be the return value of &lt;code&gt;doOtherStuff&lt;/code&gt;.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/8667330148080472494/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2013/11/fbp-in-common-lisp.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/8667330148080472494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/8667330148080472494'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2013/11/fbp-in-common-lisp.html' title='FBP in Common Lisp'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAkArhfl9xUEDxfPZ3MNCZR2U_vNBBXKJq5kQcfMXoniPXgJimUGO6cPEuzCB8PxhRw1mzcO6jRrE2pNIKnWY2tSmrW0imkOgXyBhZrbAoO3SyFvgKDhtmkmHgd2ECAesd57EQDPc1CMTi/s72-c/server-1.png" height="72" width="72"/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3016981170905406325.post-2246495937122664852</id><published>2013-10-21T09:10:00.001-07:00</published><updated>2013-10-24T08:10:28.042-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="snippets"/><title type='text'>Xmonad Tweaks</title><content type='html'>&lt;p&gt;Just a quickie to share a tweak I had to make to my &lt;code&gt;xmonad.hs&lt;/code&gt;. Not sure if there&#39;s a better way to do this, but hey.&lt;/p&gt;

&lt;p&gt;The goal was to finally, actually get working hibernation on my laptop. I usually use it in short bursts, so I just got used to shutting it down between sessions. However, I recently started using a work laptop running Windows 7 and hibernation has been useful there&lt;a href=&quot;#foot-Mon-Oct-21-121457EDT-2013&quot; name=&quot;note-Mon-Oct-21-121457EDT-2013&quot;&gt;[1]&lt;/a&gt;, and I&#39;ll be damned if the non-free shitbox is going to have a mildly useful feature that my machine doesn&#39;t.&lt;/p&gt;

&lt;p&gt;The way you get a Debian machine to hibernate or suspend is with the appropriately named &lt;code&gt;pm-hibernate&lt;/code&gt; and &lt;code&gt;pm-suspend&lt;/code&gt; commands&lt;a href=&quot;#foot-Mon-Oct-21-121501EDT-2013&quot; name=&quot;note-Mon-Oct-21-121501EDT-2013&quot;&gt;[2]&lt;/a&gt;, so I figured this would be a fairly easy key binding&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;...&lt;/span&gt;
, (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t C-&amp;lt;Delete&amp;gt;&quot;&lt;/span&gt;, spawn &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;pm-suspend&quot;&lt;/span&gt;)
, (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t &amp;lt;Delete&amp;gt;&quot;&lt;/span&gt;, spawn &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;pm-hibernate&quot;&lt;/span&gt;)
&lt;span style=&quot;color: #a0522d;&quot;&gt;...&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Unfortunately, the &lt;code&gt;pm-*&lt;/code&gt; are &lt;code&gt;root&lt;/code&gt; user commands. And Xmonad doesn&#39;t automatically prompt for a password when you do something like &lt;code&gt;su -c pm-suspend&lt;/code&gt;. &lt;i&gt;And&lt;/i&gt;, unlike with &lt;code&gt;sudo&lt;/code&gt;, you can&#39;t pass a password into &lt;code&gt;su&lt;/code&gt;. So that approach is right out.&lt;/p&gt;

&lt;p&gt;I googled around for alternatives for a little while, but What I ended up doing was finally adding myself to the &lt;code&gt;sudo&lt;/code&gt; group, and defining this function for my own nefarious purposes&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;sudoSpawn&lt;/span&gt; command &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; withPrompt &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Password&quot;&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;$&lt;/span&gt; run command
  &lt;span style=&quot;color: #a020f0;&quot;&gt;where&lt;/span&gt; run command password &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; spawn &lt;span style=&quot;color: #a0522d;&quot;&gt;$&lt;/span&gt; concat [&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;echo &quot;&lt;/span&gt;, password, &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot; | sudo -S &quot;&lt;/span&gt;, command]&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;withPrompt&lt;/code&gt; is another little utility piece I had written for some desktop changers; it&#39;s defined as&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;withPrompt&lt;/span&gt; prompt fn &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; inputPrompt xpConf prompt &lt;span style=&quot;color: #a0522d;&quot;&gt;?+&lt;/span&gt; fn&lt;/pre&gt;

&lt;p&gt;The above defined, I can now bind super-user commands to Xmonad keystrokes&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;...&lt;/span&gt;
, (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t C-&amp;lt;Delete&amp;gt;&quot;&lt;/span&gt;, sudoSpawn &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;pm-suspend&quot;&lt;/span&gt;)
, (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t &amp;lt;Delete&amp;gt;&quot;&lt;/span&gt;, sudoSpawn &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;pm-hibernate&quot;&lt;/span&gt;)
&lt;span style=&quot;color: #a0522d;&quot;&gt;...&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;with the caveat that I need to enter my password each time I invoke these. I&#39;ll see if that&#39;s too annoying. Worst case scenario, I&#39;ll pull some trickery to cache it the first time I enter it.&lt;/p&gt;

&lt;p&gt;Just in case you care, my complete &lt;code&gt;xmonad.hs&lt;/code&gt; now looks like:&lt;/p&gt;

&lt;pre&gt;&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;System.Directory&lt;/span&gt;
&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;XMonad&lt;/span&gt;
&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;XMonad.Actions.CycleWS&lt;/span&gt;
&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;XMonad.Actions.CycleWindows&lt;/span&gt;
&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;XMonad.Actions.WindowGo&lt;/span&gt;
&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;XMonad.Actions.GridSelect&lt;/span&gt;
&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;XMonad.Prompt&lt;/span&gt;
&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;XMonad.Prompt.Input&lt;/span&gt;
&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;XMonad.Util.EZConfig&lt;/span&gt;
&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;XMonad.Util.CustomKeys&lt;/span&gt;

&lt;span style=&quot;color: #a020f0;&quot;&gt;import&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;qualified&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;XMonad.StackSet&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;as&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;S&lt;/span&gt;

&lt;span style=&quot;color: #0000ff;&quot;&gt;main&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; xmonad &lt;span style=&quot;color: #a0522d;&quot;&gt;$&lt;/span&gt; conf
       &lt;span style=&quot;color: #a0522d;&quot;&gt;`additionalKeysP`&lt;/span&gt;
       [ (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t C-d C-b&quot;&lt;/span&gt;, withFilePrompt &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Pic: &quot;&lt;/span&gt; bgFolder setDesktopBackground)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;&amp;lt;Print&amp;gt;&quot;&lt;/span&gt;, withFilePrompt &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Name: &quot;&lt;/span&gt; screenshotFolder capToFile)
         
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t C-&amp;lt;Delete&amp;gt;&quot;&lt;/span&gt;, sudoSpawn &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;pm-suspend&quot;&lt;/span&gt;)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t &amp;lt;Delete&amp;gt;&quot;&lt;/span&gt;, sudoSpawn &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;pm-hibernate&quot;&lt;/span&gt;)
         
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t p&quot;&lt;/span&gt;, spawn &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;dmenu_run&quot;&lt;/span&gt;)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t C-p&quot;&lt;/span&gt;, spawn &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;dmenu_run&quot;&lt;/span&gt;)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t &amp;lt;Return&amp;gt;&quot;&lt;/span&gt;, spawn &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;xterm&quot;&lt;/span&gt;)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t e&quot;&lt;/span&gt;, runOrRaise &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;emacs&quot;&lt;/span&gt; (className &lt;span style=&quot;color: #a0522d;&quot;&gt;=?&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Emacs&quot;&lt;/span&gt;))
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t C-e&quot;&lt;/span&gt;, runOrRaise &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;emacs&quot;&lt;/span&gt; (className &lt;span style=&quot;color: #a0522d;&quot;&gt;=?&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Emacs&quot;&lt;/span&gt;))
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t b&quot;&lt;/span&gt;, spawn &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;chromium --proxy-server=\&quot;socks://localhost:9050\&quot; --incognito&quot;&lt;/span&gt;)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t C-b&quot;&lt;/span&gt;, spawn &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;chromium --proxy-server=\&quot;socks://localhost:9050\&quot; --user-agent=\&quot;Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4\&quot;&quot;&lt;/span&gt;)
         
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t s&quot;&lt;/span&gt;, nextWS)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t C-s&quot;&lt;/span&gt;, prevWS)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t w&quot;&lt;/span&gt;, toggleWS)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t C-w&quot;&lt;/span&gt;, toggleWS)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t C-t&quot;&lt;/span&gt;, windowSwap)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t t&quot;&lt;/span&gt;, windows &lt;span style=&quot;color: #228b22;&quot;&gt;S&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;swapDown)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t C-j&quot;&lt;/span&gt;, windows &lt;span style=&quot;color: #228b22;&quot;&gt;S&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;swapDown)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t j&quot;&lt;/span&gt;, windows &lt;span style=&quot;color: #228b22;&quot;&gt;S&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;focusDown)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t k&quot;&lt;/span&gt;, windows &lt;span style=&quot;color: #228b22;&quot;&gt;S&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;focusUp)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t C-k&quot;&lt;/span&gt;, windows &lt;span style=&quot;color: #228b22;&quot;&gt;S&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;swapUp)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t g&quot;&lt;/span&gt;, goToSelected defaultGSConfig)
         
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t C-&amp;lt;Space&amp;gt;&quot;&lt;/span&gt;, sendMessage &lt;span style=&quot;color: #228b22;&quot;&gt;NextLayout&lt;/span&gt;)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t C-h&quot;&lt;/span&gt;, sendMessage &lt;span style=&quot;color: #228b22;&quot;&gt;Shrink&lt;/span&gt;)
       , (&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;C-t C-l&quot;&lt;/span&gt;, sendMessage &lt;span style=&quot;color: #228b22;&quot;&gt;Expand&lt;/span&gt;)
         
       ]
  &lt;span style=&quot;color: #a020f0;&quot;&gt;where&lt;/span&gt; conf &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; defaultConfig { &lt;span style=&quot;color: #228b22;&quot;&gt;XMonad&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;startupHook &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; onStartup, modMask &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; mod4Mask }

&lt;span style=&quot;color: #b22222;&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;-------- Config Options
&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;bgFolder&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;/home/inaimathi/pictures/backgrounds/&quot;&lt;/span&gt;
&lt;span style=&quot;color: #0000ff;&quot;&gt;screenshotFolder&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;/home/inaimathi/pictures/screenshots/&quot;&lt;/span&gt;

&lt;span style=&quot;color: #0000ff;&quot;&gt;onStartup&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;::&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;X&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;()&lt;/span&gt;
&lt;span style=&quot;color: #0000ff;&quot;&gt;onStartup&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;do&lt;/span&gt;
  spawn &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;set-monitors&quot;&lt;/span&gt;
  spawn &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;pmount /dev/mmcblk0p1&quot;&lt;/span&gt;
  setDesktopBackground &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;edge-of-the-world.jpg&quot;&lt;/span&gt;

&lt;span style=&quot;color: #b22222;&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;-------- Helper Functions
&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;setDesktopBackground&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;::&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;MonadIO&lt;/span&gt; m &lt;span style=&quot;color: #a0522d;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; m &lt;span style=&quot;color: #228b22;&quot;&gt;()&lt;/span&gt;
&lt;span style=&quot;color: #0000ff;&quot;&gt;setDesktopBackground&lt;/span&gt; pic &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; spawn &lt;span style=&quot;color: #a0522d;&quot;&gt;$&lt;/span&gt; concat [&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;feh --no-xinerama --bg-fill &quot;&lt;/span&gt;, bgFolder, pic]
        
&lt;span style=&quot;color: #0000ff;&quot;&gt;capToFile&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;::&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;MonadIO&lt;/span&gt; m &lt;span style=&quot;color: #a0522d;&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;String&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;-&amp;gt;&lt;/span&gt; m &lt;span style=&quot;color: #228b22;&quot;&gt;()&lt;/span&gt;
&lt;span style=&quot;color: #0000ff;&quot;&gt;capToFile&lt;/span&gt; picName &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; spawn &lt;span style=&quot;color: #a0522d;&quot;&gt;$&lt;/span&gt; concat [&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;import &quot;&lt;/span&gt;, screenshotFolder, picName]

&lt;span style=&quot;color: #0000ff;&quot;&gt;sudoSpawn&lt;/span&gt; command &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; withPrompt &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;Password&quot;&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;$&lt;/span&gt; run command
  &lt;span style=&quot;color: #a020f0;&quot;&gt;where&lt;/span&gt; run command password &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; spawn &lt;span style=&quot;color: #a0522d;&quot;&gt;$&lt;/span&gt; concat [&lt;span style=&quot;color: #8b2252;&quot;&gt;&quot;echo &quot;&lt;/span&gt;, password, &lt;span style=&quot;color: #8b2252;&quot;&gt;&quot; | sudo -S &quot;&lt;/span&gt;, command]

&lt;span style=&quot;color: #b22222;&quot;&gt;--&lt;/span&gt;&lt;span style=&quot;color: #b22222;&quot;&gt;-------- Utility
&lt;/span&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;windowSwap&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;do&lt;/span&gt;
  windows &lt;span style=&quot;color: #228b22;&quot;&gt;S&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;focusDown
  windows &lt;span style=&quot;color: #228b22;&quot;&gt;S&lt;/span&gt;&lt;span style=&quot;color: #a0522d;&quot;&gt;.&lt;/span&gt;swapUp

&lt;span style=&quot;color: #0000ff;&quot;&gt;xpConf&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; defaultXPConfig { position &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #228b22;&quot;&gt;Top&lt;/span&gt; }

&lt;span style=&quot;color: #0000ff;&quot;&gt;withPrompt&lt;/span&gt; prompt fn &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; inputPrompt xpConf prompt &lt;span style=&quot;color: #a0522d;&quot;&gt;?+&lt;/span&gt; fn

&lt;span style=&quot;color: #0000ff;&quot;&gt;withCompletingPrompt&lt;/span&gt; prompt completions fn &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; 
  inputPromptWithCompl xpConf prompt comp &lt;span style=&quot;color: #a0522d;&quot;&gt;?+&lt;/span&gt; fn
  &lt;span style=&quot;color: #a020f0;&quot;&gt;where&lt;/span&gt; comp &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; mkComplFunFromList completions

&lt;span style=&quot;color: #0000ff;&quot;&gt;withFilePrompt&lt;/span&gt; prompt directory fn &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #a020f0;&quot;&gt;do&lt;/span&gt;
  files &lt;span style=&quot;color: #a0522d;&quot;&gt;&amp;lt;-&lt;/span&gt; liftIO &lt;span style=&quot;color: #a0522d;&quot;&gt;$&lt;/span&gt; getDirectoryContents directory
  &lt;span style=&quot;color: #a020f0;&quot;&gt;let&lt;/span&gt; fs &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; filter relevant files
      relevant f &lt;span style=&quot;color: #a0522d;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #8b2252;&quot;&gt;&#39;.&#39;&lt;/span&gt; &lt;span style=&quot;color: #a0522d;&quot;&gt;/=&lt;/span&gt; head f
  withCompletingPrompt prompt fs fn&lt;/pre&gt;


&lt;hr /&gt;
&lt;h5&gt;Footnotes&lt;/h5&gt;
&lt;p&gt;1 - &lt;a href=&quot;#note-Mon-Oct-21-121457EDT-2013&quot; name=&quot;foot-Mon-Oct-21-121457EDT-2013&quot;&gt;[back]&lt;/a&gt; - Granted, because the boot time on that machine is something like 5 minutes instead of the 12 seconds I&#39;m used to waiting, Hibernate is a goddamn necessity, but I digress.&lt;/p&gt;

&lt;p&gt;2 - &lt;a href=&quot;#note-Mon-Oct-21-121501EDT-2013&quot; name=&quot;foot-Mon-Oct-21-121501EDT-2013&quot;&gt;[back]&lt;/a&gt; - Ideally, I&#39;d just be using hibernate, but there are some issues. I&#39;ve upgraded my ram since installing the OS, which means that my &lt;code&gt;swap&lt;/code&gt; partition isn&#39;t big enough to store a memory dump, and I can&#39;t seem to resize it with &lt;code&gt;gparted&lt;/code&gt;, with or without &lt;code&gt;swapoff&lt;/code&gt;/&lt;code&gt;swapon&lt;/code&gt; magic. Luckily, I&#39;ve had a larger hard drive waiting for me to crack open the box and configure it to my liking, so I&#39;ll just do that this week rather than procrastinating. In the meantime though, I&#39;m &lt;code&gt;suspend&lt;/code&gt;ing instead.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://langnostic.blogspot.com/feeds/2246495937122664852/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://langnostic.blogspot.com/2013/10/xmonad-tweaks.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/2246495937122664852'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3016981170905406325/posts/default/2246495937122664852'/><link rel='alternate' type='text/html' href='http://langnostic.blogspot.com/2013/10/xmonad-tweaks.html' title='Xmonad Tweaks'/><author><name>Inaimathi</name><uri>http://www.blogger.com/profile/14277727122990903016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>