beowulf/docs/codox/values.html

263 lines
41 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>The properties of the system, and their values</title><link rel="icon" type="image/x-icon" href="../img/beowulf_logo_favicon.png" /><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Beowulf</span> <span class="project-version">0.3.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 "><a href="further_reading.html"><div class="inner"><span>Further Reading</span></div></a></li><li class="depth-1 "><a href="intro.html"><div class="inner"><span>beowulf</span></div></a></li><li class="depth-1 "><a href="mexpr.html"><div class="inner"><span>Interpreting M-Expressions</span></div></a></li><li class="depth-1 current"><a href="values.html"><div class="inner"><span>The properties of the system, and their values</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>beowulf</span></div></div></li><li class="depth-2 branch"><a href="beowulf.bootstrap.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>bootstrap</span></div></a></li><li class="depth-2 branch"><a href="beowulf.cons-cell.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>cons-cell</span></div></a></li><li class="depth-2 branch"><a href="beowulf.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="beowulf.gendoc.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>gendoc</span></div></a></li><li class="depth-2 branch"><a href="beowulf.host.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>host</span></div></a></li><li class="depth-2 branch"><a href="beowulf.interop.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>interop</span></div></a></li><li class="depth-2 branch"><a href="beowulf.io.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>io</span></div></a></li><li class="depth-2 branch"><a href="beowulf.manual.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>manual</span></div></a></li><li class="depth-2 branch"><a href="beowulf.oblist.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>oblist</span></div></a></li><li class="depth-2 branch"><a href="beowulf.read.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>read</span></div></a></li><li class="depth-2"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>reader</span></div></div></li><li class="depth-3 branch"><a href="beowulf.reader.char-reader.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>char-reader</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.generate.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>generate</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.macros.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>macros</span></div></a></li><li class="depth-3 branch"><a href="beowulf.reader.parser.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>parser</span></div></a></li><li class="depth-3"><a href="beowulf.reader.simplify.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>simplify</span></div></a></li></ul></div><div class="document" id="content"><div class="doc"><div class="markdown"><h1><a href="#the-properties-of-the-system-and-their-values" name="the-properties-of-the-system-and-their-values"></a>The properties of the system, and their values</h1>
<h2><a href="#here-be-dragons" name="here-be-dragons"></a>here be dragons</h2>
<p>Lisp is the list processing language; that is what its name means. It processes data structures built of lists - which may be lists of lists, or lists of numbers, or lists of any other sort of data item provided for by the designers of the system.</p>
<p>But how is a list, in a computer, actually implemented?</p>
<p>Theyre implemented as pairs, or, as the manual sometimes rather delightfully called them, doublets. Pairs of what? Pairs of pointers. Of the two pointers of a pair, the first points to the current entry of the list, and the second, by default, points to the remainder of the list, or, if the end of the list has been reached, to a special datum known as <code>NIL</code> which among other things indicates that the end of the list has been reached. The pair itself is normally referred to as a cons cell for reasons which are nerdy and not important just now (all right, because they are constructed using a function called <code>cons</code>, which is in itself believed to be simply an abbreviation of construct).</p>
<p>Two functions are used to access the two pointers of the cell. In modern Lisps these functions are called <code>first</code> and <code>rest</code>, because a lot of people who arent greybeards find these names easier. But they arent the original names. The original names were <code>CAR</code> and <code>CDR</code>.</p>
<p>Why?</p>
<h2><a href="#history" name="history"></a>History</h2>
<p>Lisp was originally written on an <a href="https://comphist.dhlab.mit.edu/archives/story/IBM_mechanics">IBM 704 computer at Massachusetts Institute of Technology</a>, almost seventy years ago. </p>
<p>The machine had registers which were not eight, or sixteen, or thirty two, or sixty four, bits wide, or any other number which would seem rational to modern computer scientists, but thirty six. Myth - folk memory - tells us that the machines memory was arranged in pages. As I understand it (but this truly is folk memory) the offset within the page of the word to be fetched was known as the decrement, while the serial number of the page in the addressing sequence was known as the address. To fetch a word from memory, you first had to select the page using the address, and secondly the word itself using the decrement. So there were specific instructions for selecting the address, and the decrement, from the register separately.</p>
<p>There were two mnemonics for the machine instructions used to access the content of these registers, respectively:</p>
<dl>
<dt>CAR</dt>
<dd>
<p><em>Contents of the Address part of Register</em>; and</p></dd>
<dt>CDR</dt>
<dd>
<p><em>Contents of the Decrement part of Register</em>.</p></dd>
</dl>
<p>Is this actually true?</p>
<p>I think so. If you look at <a href="https://bitsavers.org/pdf/mit/rle_lisp/LISP_I_Programmers_Manual_Mar60.pdf#page=89">page 80 of the Lisp 1 Programmers Manual</a>, you will see this:</p>
<pre><code class="IBM704">TEN (the TEN-Mode is entered)
O CAR (((A,B),C)) () \
|
:1 CDR ((D,(E,F))) () |
&gt; Type ins
:2 CONS ((G,H), |
|
230 (I,J)) () /
RLN | | oo 7 a |
O14 (read lines O and 1)
</code></pre>
<p>Of course, this isnt proof. If <code>CAR</code> and <code>CDR</code> used here are standard IBM 704 assembler mnemonics as I believe they are then what is <code>CONS</code>? Its used in a syntactically identical way. If it also is an assembler mnemonic, then its hard to believe that, as legend relates, it is short for construct; on the other hand, if its a label representing an entry point into a subroutine, then why should <code>CAR</code> and <code>CDR</code> not also be labels?</p>
<hr />
<p><strong>Edited 3<sup>rd</sup> April to add:</strong> Ive found a document, not related to Lisp (although John McCarthy is credited as one of the authors), which does confirm or strictly, amend the story. This is the <a href="http://bitsavers.org/pdf/mit/computer_center/Coding_for_the_MIT-IBM_704_Computer_Oct57.pdf">CODING for the MIT-IBM 704 COMPUTER</a>, dating from October 1957. The registers of the 704 were divided into four parts, named respectively the prefix part, the address part, the tag part, and the decrement part, of 3, 15, 3, and 15 bits respectively. The decrement part was not used in addressing; that part of the folklore I was taught isnt right. But the names are correct. Consider <a href="http://bitsavers.org/pdf/mit/computer_center/Coding_for_the_MIT-IBM_704_Computer_Oct57.pdf#page=145">this excerpt</a> :</p>
<blockquote>
<p>The address, tag and decrement parts of symbolic instructions are given in that order. In some cases the decrement, tag or address parts are not necessary; therefore the following combinations where OP represents the instruction abbreviation are permissible.</p>
</blockquote>
<p>This doesnt prove there were individual machine instructions with the mnemonics <code>CAR</code> and <code>CDR</code>; in fact, Im going to say with some confidence that there were not, by reference to <a href="http://bitsavers.org/pdf/mit/computer_center/Coding_for_the_MIT-IBM_704_Computer_Oct57.pdf#page=170">the table of instructions</a> appended to the same document. The instructions do have three letter mnemonics, and they do use A and D as abbreviations for address and decrement respectively, but <code>CAR</code> and <code>CDR</code> are not included.</p>
<p>So it seems probable that <code>CAR</code> and <code>CDR</code> were labels for subroutines, as I hypothesised above. But they were quite likely pre-existing subroutines, in use before the instantiation of the Lisp project, because they would be generally useful; and the suggestion that they are contractions of contents of the address part and contents of the decrement part, respectively, seem confirmed.</p>
<p>And, going further down the rabbit hole, <a href="https://dl.acm.org/doi/pdf/10.1145/800055.802047#page=3">theres this</a>. In 1957, before work on the Lisp project started, McCarthy was writing functions to add list processing to the then-new FORTRAN language, on the very same IBM 704 machine. </p>
<blockquote>
<p>in this time any function that delivered integer values had to have a first letter X. Any function (as opposited to subroutines) had to have a last letter F in its name. Therefore the functions selecting parts of the IBM704 memory register (word) were introduced to be XCSRF, XCPRF, XCDRF, XCTRF and XCARF</p>
</blockquote>
<hr />
<p>I think that the answer has to be that if <code>CAR</code> and <code>CDR</code> had been named by the early Lisp team John McCarthy and his immediate colleagues they would not have been named as they were. If not <code>FRST</code> and <code>REST</code>, as in more modern Lisps, then something like <code>P1</code> and <code>P2</code>. <code>CAR</code> and <code>CDR</code> are distinctive and memorable (and therefore in my opinion worth preserving) because they very specifically name the parts of a cons cell and of nothing else.</p>
<p>Lets be clear, here: when <code>CAR</code> and <code>CDR</code> are used in Lisp, they are returning pointers, certainly but not in the sense that one points to a page and the other to a word. Each is an offset into a cell array, which is almost certainly an array of single 36 bit words held on a single page. So both are in effect being used as decrements. Their use in Lisp is an overload onto their original semantic meaning; they are no longer being used for the purpose for which they are named.</p>
<p>As far as I can tell, these names first appear in print in 1960, both in the Lisp 1 Programmers Manual referenced above, and in McCarthys paper <a href="https://web.archive.org/web/20230328222647/http://www-formal.stanford.edu/jmc/recursive.pdf">Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I</a>. The paper was published in April so was presumably written in 1959</p>
<h2><a href="#grey-anatomy" name="grey-anatomy"></a>Grey Anatomy</h2>
<h3><a href="#the-object-list" name="the-object-list"></a>The Object List</h3>
<p>Lisp keeps track of values by associating them with names. It does so by having what is in effect a global registry of all the names it knows to which values are attached. This being a list processing language, that was of course, in early Lisps, a list: a single specialised first class list known as the object list, or <code>oblist</code> for short.</p>
<p>Of course, a list need not just be a list of single items, it can be a list of pairs: it can be a list of pairs of the form <code>(name . value)</code>. Hold onto that, because I want to talk about another fundamental part of a working Lisp system, the stack. </p>
<h3><a href="#the-stack" name="the-stack"></a>The Stack</h3>
<p>Considering the case of pure interpreter first, lets think about how a function keeps track of the data its working on. In order to do its work, it probably calls other functions, to which it passes off data, and they in turn probably call further functions. So, when control returns to our first function, how does it know where its data is? The answer is that each function pushes its argument bindings onto the stack when it starts work, and pops them off again when it exits. So when control returns to a function, its own data is still on the top of the stack. Or, to be precise, actually it doesnt; in practice the function <a href="https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf#page=79"><code>EVAL</code></a> does it for each function in turn. But it doesnt matter: it gets done.</p>
<p>What is this stack? Well, its a list of <code>(name . value)</code> pairs. At least, it is in pure Lisps; <a href="https://clojure.org/">Clojure</a>, because it runs on the <a href="https://en.wikipedia.org/wiki/Java_virtual_machine">Java Virtual Machine</a> and interoperates with other software running on the JVM, uses the JVM stack which is a permanently reserved vector of memory never used for anything else. Consequently it cannot be very large; and the consequence of that is that its very easy to crash JVM programs because theyve run out of stack space.</p>
<p>The advantage of organising your stack as a vector is that on average its usually slightly more memory efficient, and that its somewhat faster to access. The disadvantage is you need a contiguous block of memory for it, and once youve run out, youve at best lost both those advantages but in the normal case your program just crashes. Also, the memory youve reserved for the stack isnt available for any other use, even during the most of the time that the stack isnt using most of it. So of course theres a temptation to keep the amount reserved for the stack as small as possible.</p>
<p>Its this brutal fragility of vector stacks which are used by most modern computer languages which makes software people so wary of fully exploiting the beauty and power of recursion, and I really think thats a shame.</p>
<p>The advantage of organising your stack as a list is that, while there is any memory left on the machine at all, you cannot run out of stack.</p>
<p>### The Spine</p>
<p>So, theres an object list where you associate names and values, and theres a stack where you associate names and values. But, why do they have to be different? And why do you have to search in two places to find the value of a name?</p>
<p>The answer is or it was, and arguably it should be that you dont. The stack can simply be pushed onto the front of the object list. This has multiple advantages. The first and most obvious is that you only have to search in one place for the value associated with a name. </p>
<p>The second is more subtle: a function can mask a variable in the object list by binding the same name to a new value, and the functions to which it then calls will only see that new value. This is useful if, for example, printed output is usually sent to the users terminal, but for a particular operation you want to send it to a line printer or to a file on disk. You simply rebind the name of the standard output stream to your chosen output stream, and call the function whose output you want to redirect.</p>
<p>So, in summary, theres a lot of merit in making the stack and the object list into a single central structure on which the architecture of our Lisp system is built. But theres more we need to record, and its important.</p>
<p>### Fields and Properties</p>
<p>No, Im not banging on about <a href="https://www.journeyman.cc/blog/tags-output/Levelling/">land reform</a> again! Im not a total monomaniac!</p>
<p>But theres more than one datum we may want to associate with a single name. A list can be more than a set of bindings between single names and single values. Theres more than one thing, for example, that I know about my friend Lucy. I know her age. I know her address. I know her height. I know her children. I know her mother. All of this information and much more should be associated with her.</p>
<p>In conventional computing systems wed use a table. Wed put into the table a field a column for each datum we wanted to store about a class of things of interest. And wed reserve space to store that datum for every record, whether every record had something to go there of not. Furthermore, wed have to reserve space in each field for the maximum size of the datum to be stored in it so if we needed to store full names for even some of the people we knew, and one of the people whose full name we needed to store (because hes both very important and very irascible) was <em>Charles Philip Arthur George Windsor</em>, then wed have to reserve space for thirty-six characters for the full name of everyone in our records, even if for most of them half that would be enough.</p>
<p>But if instead of storing a table for each sort of thing on which we hold data, and a row in that table for each item of that sort on which we store data, we simply tagged each thing on which we hold data with those things which are interesting about them? We could tag my friend Lucy with the fact shes on pilgrimage, and what her pilgrimage route is. Those arent things we need to know about most people, it would be absurdly wasteful to add a column to a <code>person</code> table to record <code>pilgrimage route</code>. So in a conventional data system we would lose that data.</p>
<p>Lisp has had, right back from the days of Lisp 1.5 so, for sixty-five years a different solution. We can give every symbol arbitrarily many, arbitrarily different, properties. A property is a <code>(name . value)</code> pair. We dont have to store the same properties for every object. The values of the properties dont have to have a fixed size, and they dont have to take up space they dont need. Its like having a table with as many fields as we choose, and being able to add more fields at any time.</p>
<p>So, in summary, I knew, in building Beowulf, that Id have to implement property lists. I just didnt know how I was going to do it.</p>
<h2><a href="#archaeology" name="archaeology"></a>Archaeology</h2>
<p>What Im doing with Beowulf is trying to better understand the history of Lisp by reconstructing a very early example; in this case, Lisp 1.5, from about 1962, or sixty one years ago.</p>
<p>I had had the naive assumption that entries on the object list in early Lisps had their <code>CAR</code> pointing to the symbol and their <code>CDR</code> pointing to the related value. Consequently, in building <a href="https://github.com/simon-brooke/beowulf">beowulf</a>, I could not work out where the property list went. More careful reading of <a href="https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf#page=67">the text</a> implies, but does not explicitly state, that my naive assumption is wrong.</p>
<p>Instead, it appears that the <code>CAR</code> points to the symbol, as expected, but the <code>CDR</code> points to the property list; and that on the property list there are privileged properties at least as follows:</p>
<dl>
<dt>APVAL</dt>
<dd>the simple straightforward ordinary value of the symbol, considered as a variable;</dd>
<dt>EXPR</dt>
<dd>the definition of the function considered as a normal lambda expression (arguments to be evaluated before applying);</dd>
<dt>FEXPR</dt>
<dd>the definition of a function which should be applied to unevaluated arguments (what InterLisp and Portable Standard Lisp would call <a href="https://citeseerx.ist.psu.edu/document?repid=rep1&amp;type=pdf&amp;doi=fe0f4f19cee0c607d7b229feab26fc9ed559fc9c#page=9"><em>nlambda</em></a>);</dd>
<dt>SUBR</dt>
<dd>the definition of a compiled subroutine which should be applied to evaluated arguments;</dd>
<dt>FSUBR</dt>
<dd>the definition of a compiled subroutine which should be applied to unevaluated arguments.</dd>
</dl>
<p>I think there was also another privileged property value which contained the property considered as a constant, but I havent yet confirmed that.</p>
<p>From this it would seem that Lisp 1.5 was not merely a <a href="http://xahlee.info/emacs/emacs/lisp1_vs_lisp2.html">Lisp 2</a> but in fact a Lisp 6, with six effectively first class namespaces. In fact its not as bad as that, because of the way <a href="https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf#page=79"><code>EVAL</code></a> is evaluated.</p>
<p>Essentially the properties are tried in turn, and only the first value found is used. Thus the heirarchy is</p>
<ol>
<li>APVAL</li>
<li>EXPR</li>
<li>FEXPR</li>
<li>SUBR</li>
<li>FSUBR</li>
</ol>
<p>This means that, while the other potential values can be retrieved from the property list, interpreted definitions (if present) will always be preferred to uninterpreted definitions, and lambda function definitions (which evaluate their arguments), where present, will always be preferred to non-lamda definitions, which dont.</p>
<p><strong>BUT NOTE THAT</strong> the <code>APVAL</code> value is sought only when seeking a variable value for the symbol, while the others are only when seeking a function value, so Lisp 1.5 is a Lisp 2, not a Lisp 1. I strongly believe that this is wrong: a function is a value, and should be treated as such. But at the same time I do acknowledge the benefit of being able to store both source and compiled forms of the function as properties of the same symbol.</p>
<h2><a href="#the-persistent-problem" name="the-persistent-problem"></a>The persistent problem</h2>
<p>Theres a view in modern software theory with which I strongly hold that data should be immutable. Data that changes under you is the source of all sorts of bugs. And in modern multi threaded systems, the act of reading a datum whilst some other process is writing it, or worse, two processes attempting simultaneously to write the same datum, is a source of data corruption and even crashes. So Im very wary of mutable data; and, in modern systems where we normally have a great deal of space and a lot of processor power, making fresh copies of data structures containing the change we wanted to make is a reasonable price to pay for avoiding a whole class of bugs.</p>
<p>But early software was not like that. It was always constrained by the limits of the hardware on which it ran, to a degree that we are not. And the experience that we now have of the problems caused by mutable data, they did not have. So its core to the design of Lisp 1.5 that its lists are mutable; and, indeed, one of the biggest challenges in writing Beowulf has been <a href="https://github.com/simon-brooke/beowulf/blob/master/src/beowulf/cons_cell.clj#L19">implementing mutable lists in Clojure</a>, a language carefully designed to prevent them.</p>
<p>But, just because Lisp 1.5 lists can be mutable, should they be? And when should they be?</p>
<p>The problem here is that <a href="#the_spine">spine of the system</a> I talked about earlier. If we build the execution stack on top of the oblist as at present I do then if we make a new version of the oblist with changes in it, the new changes will not be in the copy of the oblist that the stack is built on top of; and consequently, theyll be invisible to the running program.</p>
<p>What I do at present, and what I think may be good enough, is that each time execution returns to the read-eval-print loop, the REPL, the users command line, I rebuild a new execution stack on the top of the oblist as it exists now. So, if the last operation modified the oblist, the next operation will see the new, modified version. But if someone tried to run some persistent program which was writing stuff to property values and hoping to read them back in the same computation, that wouldnt work, and it would be a very hard bug to trace down.</p>
<p>So my options are:</p>
<ol>
<li>To implement <code>PUT</code> and <code>GET</code> in Clojure, so that they can operate on the current copy of the object list, not the one at the base of the stack. Im slightly unwilling to do that, because my objective is to make Beowulf ultimately as self-hosting as possible.</li>
<li>To implement <code>PUT</code> and <code>GET</code> in Lisp, and have them destructively modify the working copy of the object list.</li>
</ol>
<p>Neither of these particularly appeal.</p>
<h2><a href="#how-property-lists-should-work" name="how-property-lists-should-work"></a>How property lists should work</h2>
<p>Im still not fully understanding how property lists in Lisp 1.5 are supposed to work. </p>
<h3><a href="#list-format" name="list-format"></a>List format</h3>
<p>Firstly, are they association lists comprising dotted pairs of <code>(property-name . value)</code>, i.e.: </p>
<blockquote>
<p>((property-name<sub>1</sub> . value<sub>1</sub>) (property-name<sub>2</sub> . value<sub>2</sub>) … (property-name<sub>n</sub> . value<sub>n</sub>))</p>
</blockquote>
<p>I have assumed so, and that is what I presently intend to implement, but the diagrams on <a href="https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf#page=67">pages 59 and 60</a> seem rather to show a flat list of interleaved names and values:</p>
<blockquote>
<p>(property-name<sub>1</sub> value<sub>1</sub> property-name<sub>2</sub> value<sub>2</sub> … property-name<sub>n</sub> value<sub>n</sub>)</p>
</blockquote>
<p>I cannot see what the benefit of this latter arrangement is, and Im unwilling to do it, although I think it may be what was done. But if it was done that way, <em>why</em> was it done that way? These were bright people, and they certainly knew about association lists. So… Im puzzled.</p>
<h3><a href="#function-signatures" name="function-signatures"></a>Function signatures</h3>
<p>To associate the value of a property with a symbol, we need three things: we need the symbol, we need the property name, and we need the value. For this reason, <a href="https://www.softwarepreservation.org/projects/LISP/utah/USCP-Portable_Standard_LISP_Users_Manual-TR_10-1984.pdf#page=44">Portable Standard Lisp</a> and others has a function <code>put</code> with three arguments:</p>
<blockquote>
<p><code>(Put U:id IND:id PROP:any)</code>: any The indicator <code>IND</code> with the property <code>PROP</code> is placed on the property list of the id <code>U</code>. If the action of Put occurs, the value of <code>PROP</code> is returned. If either of <code>U</code> and <code>IND</code> are not ids the type mismatch error occurs and no property is placed. <code>(Put 'Jim 'Height 68)</code> The above returns <code>68</code> and places <code>(Height . 68)</code> on the property list of the id <code>Jim</code></p>
</blockquote>
<p>Cambridge Lisp is identical to this except in lower case. <a href="https://larrymasinter.net/86-interlisp-manual-opt.pdf#page=37">InterLisp</a> and several others have <code>putprop</code>:</p>
<blockquote>
<p><code>(PUTPROP ATM PROP VAL) [Function]</code> Puts the property <code>PROP</code> with value <code>VAL</code> on the property list of <code>ATM</code>. <code>VAL</code> replaces any previous value for the property <code>PROP</code> on this property list. Returns <code>VAL</code>.</p>
</blockquote>
<p>The execrable Common Lisp uses its execrable macro <a href="https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node108.html"><code>setf</code></a> but really the less said about that the better.</p>
<p>So I was looking for a function of three arguments to set properties, and I didnt find one. </p>
<p>Theres a function <code>DEFINE</code> which takes one argument, an association list of pairs:</p>
<pre><code class="lisp"> (function-name . function-definition)`
</code></pre>
<p>So how does that work, if what its doing is setting properties? If all youre passing is pairs of name and definition, where does the property name come from?</p>
<p>The answer is as follows, taken from <a href="https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf#page=66">the manual</a>:</p>
<blockquote>
<h4><a href="#define-x-expr-pseudo-function" name="define-x-expr-pseudo-function"></a>define [x] : EXPR pseudo-function</h4>
<p>The argument of <code>define</code>, <code>x</code>, is a list of pairs</p>
<blockquote>
<p>((u<sub>l</sub> v<sub>l</sub>) (u<sub>2</sub> v<sub>2</sub>) … (u<sub>n</sub> v<sub>n</sub>))</p>
</blockquote>
<p>where each <code>u</code> is a name and each <code>v</code> is a λ-expression for a function . For each <code>pair</code>, define puts an <code>EXPR</code> on the property list for <code>u</code> pointing to <code>v</code>. The function of <code>define</code> puts things on at the front of the property list. The value of <code>define</code> is the list of <code>u</code>s.</p>
</blockquote>
<p>So, in fact, the value of the property being set by <code>define</code> is fixed: hard wired, not parameterised. That seems an astonishing decision, until you realise that Lisp 1.5s creators werent creating their functions one by one, in a playful exploration with their system, but entering them in a batch.</p>
<h2><a href="#learning-by-doing" name="learning-by-doing"></a>Learning by doing</h2>
<p>In fact, when I got over my surprise, I realised that that <code>(name . function-definition)</code> list is actually very much like this, which is an excerpt from a sysout from a Beowulf prototype:</p>
<pre><code class="lisp">(...
(MAPLIST LAMBDA (L F)
(COND ((NULL L) NIL)
((QUOTE T) (CONS (F (CAR L)) (MAPLIST (CDR L) F)))))
(MEMBER LAMBDA (A X)
(COND ((NULL X) (QUOTE F))
((EQ A (CAR X)) (QUOTE T))
((QUOTE T) (MEMBER A (CDR X)))))
(MINUSP LAMBDA (X) (LESSP X 0))
(NOT LAMBDA (X)
(COND (X (QUOTE NIL))
((QUOTE T) (QUOTE T))))
(NULL LAMBDA (X)
(COND ((EQUAL X NIL) (QUOTE T))
(T (QUOTE F))))
...)
</code></pre>
<p>I was looking at <code>DEFINE</code> and thinking, why would one ever want to do that? and then I found that, behind the scenes, I was actually doing it myself.</p>
<p>Because the point of a sysout is you dont write it. The point about the REPL the Read Eval Print Loop which is the heart of the interactive Lisp development cycle, where you sit playing with things and fiddling with them interactively, and where when one thing works you get onto the next without bothering to make some special effort to record it.</p>
<p>The point of a sysout is that, at the end of the working day, you invoke one function</p>
<table>
<thead>
<tr>
<th>Function </th>
<th>Type </th>
<th>Signature </th>
<th>Implementation </th>
<th>Documentation </th>
</tr>
</thead>
<tbody>
<tr>
<td>SYSOUT </td>
<td>Host function </td>
<td>(SYSOUT); (SYSOUT FILEPATH) </td>
<td>SUBR </td>
<td>Dump the current content of the object list to file. If no <code>filepath</code> is specified, a file name will be constructed of the symbol <code>Sysout</code> and the current date. File paths will be considered relative to the filepath set when starting Lisp. </td>
</tr>
</tbody>
</table>
<p>At the start of the next working day, you load that sysout in and continue your session.</p>
<p>The sysout captures the entire working state of the machine. No-one types it in, as an operation in itself. Instead, data structures corpuses of functions among them simply build up on the object list almost casually, as a side effect of the fact that youre enjoying exploring your problem and finding elegant ways of solving it. So <code>SYSOUT</code> and <code>SYSIN</code> seem to me, as someone who all his adult life has worked with Lisp interactively, as just an automatic part of the cycle of the day.</p>
<h2><a href="#the-process-of-discovery" name="the-process-of-discovery"></a>The process of discovery</h2>
<p>The thing is, I dont think anyone is ever going to use Beowulf the way Lisp 1.5 was used. I mean, probably, no one is ever going to use Beowulf at all; but if they did they wouldnt use Beowulf the way Lisp 1.5 was used. </p>
<p>Im a second generation software person. I have worked, in my career, with two people who personally knew and had worked with <a href="https://en.wikipedia.org/wiki/Alan_Turing">Alan Turing</a>. I have worked with, and to an extent been mentored by, <a href="https://www.bcs.org/articles-opinion-and-research/manchester-s-place-in-computing-history-marked/">Chris Burton</a>, who in his apprenticeship was part of the team that built the Manchester Mark One, and who in his retirement led the team who restored it. But I never knew the working conditions they were accustomed to. In my first year at university we used card punches, and, later, when we had a bit of seniority, teletypewriters (yes, thats what TTY stands for), but by the time Id completed my undergraduate degree and become a research associate I had a Xerox 1108 workstation with a huge bitmapped graphic screen, and an optical mouse, goddamit, running InterLisp, all to myself.</p>
<p>People in the heroic age did not have computers all to themselves. They did not have terminals all to themselves. They didnt sit at a terminal experimenting in the REPL. They wrote their algorithms in pencil on paper. When they were certain theyd got it right, theyd use a card punch to punch a deck of cards carrying the text of the program, and then they were certain theyd got <em>that</em> right, theyd drop it into the input hopper. Some time later their batch would run, and the operator would put the consequent printout into their pigeon hole for them to collect.</p>
<p>(They wrote amazingly clean code, those old masters. I could tell you a story about Chris Burton, the train, and the printer driver, that software people of today simply would not believe. But its true. And I think that what taught them that discipline was the high cost of even small errors.)</p>
<p>Lisp 1.5 doesnt have <code>PUT</code>, <code>PUTPROP</code> or <code>DEFUN</code> because setting properties individually, defining functions individually one at a time, was not something they ever thought about doing. And in learning that, Ive learned more than I ever expected to about the real nature of Lisp 1.5, and the (great) people who wrote it.</p>
<hr />
<h2><a href="#deeper-delving" name="deeper-delving"></a>Deeper delving</h2>
<p>After writing, and publishing, this essay, I went on procrastinating, which is what I do when Im sure Im missing something; and to procrastinate, I went on reading the earliest design documents of Lisp I could find. And so I came across the MIT AI teams first ever memo, written by John McCarthy in September 1958. And in that, I find this:</p>
<blockquote>
<p>3.2.1. First we have those that extract parts of a 704 word and form a word from parts. We shall distinguish the following parts of a word and indicate each of them by a characteristic letter.</p>
<table>
<thead>
<tr>
<th>Letter </th>
<th>Description </th>
</tr>
</thead>
<tbody>
<tr>
<td>w </td>
<td>the whole word </td>
</tr>
<tr>
<td>p </td>
<td>the prefix (bits s, 1, 2) </td>
</tr>
<tr>
<td>i </td>
<td>the indicator (bits 1 and 2) </td>
</tr>
<tr>
<td>s </td>
<td>the sign bit </td>
</tr>
<tr>
<td>d </td>
<td>the decrement (bits 3-17) </td>
</tr>
<tr>
<td>t </td>
<td>the tag (bits 18-20) </td>
</tr>
<tr>
<td>a </td>
<td>the address (bits 21-35) </td>
</tr>
</tbody>
</table>
</blockquote>
<p>In the discussion of functions which access properties on <a href="https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf#page=66">page 58 of the Lisp 1.5 programmers manual</a>, the word indicator is used in preference to symbol for the name of a property: for example</p>
<blockquote>
<p>The function <code>deflist</code> is a more general defining function. Its first argument is a list of pairs as for define. Its second argument is the <em>indicator</em> that is to be used. After <code>deflist</code> has been executed with (u<sub>i</sub> v<sub>i</sub>) among its first argument, the property list of u<sub>i</sub> will begin:</p>
<p>If <code>deflist</code> or <code>define</code> is used twice on the same object with the same <em>indicator</em>, the old value will be replaced by the new one.</p>
</blockquote>
<p>(my emphasis).</p>
<p>That use of indicator has been nagging at me for a week. It looks like a term of art. If its just an ordinary atomic symbol, why isnt it called a symbol?</p>
<p>Is it an indicator in the special sense of the indicator part of the machine word? If it were, then the property list could just be a flat list of values. And whats been worrying and surprising me is that property lists are shown in the manual as flat lists. Eureka? I dont <em>think</em> so.</p>
<p>The reason I dont think so is that there are only two bits in the indicator part of the word, so only four distinct values; whereas we know that Lisp 1.5 has (at least) five distinct indicator values, <code>APVAL</code>, <code>EXPR</code>, <code>FEXPR</code>, <code>SUBR</code> and <code>FSUBR</code>.</p>
<p>Furthermore, on <a href="https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf#page=47">page 39</a>, we have:</p>
<blockquote>
<p>A property list is characterized by having the special constant 77777<sub>8</sub> (i. e., minus 1) as the first element of the list. The rest of the list contains various properties of the atomic symbol. Each property is preceded by an <em>atomic symbol</em> which is called its <em>indicator</em>.</p>
</blockquote>
<p>(again, my emphasis)</p>
<p>But Im going to hypothesise that the properties were originally intended to be discriminated by the indicator bits in the cons cell, that they were originally coded that way, and that there was some code which depended on property lists being flat lists; and that, when it was discovered that four indicators were not enough and that something else was going to have to be used, the new format of the property list using atomic symbols as indicators was bodged in.</p>
<hr />
<p>So what this is about is Ive spent most of a whole day procrastinating, because Im not exactly sure how Im going to make the change Ive got to make. Versions of Beowulf up to and including 0.2.1 used the naive understanding of the architecture; version 0.3.0 <em>should</em> use the corrected version. But before it can, I need to be reasonably confident that I understand what the correct solution is.</p>
<p>I <em>shall</em> implement <code>PUT</code>, even though it isnt in the spec, because its a useful building block on which to build <code>DEFINE</code> and <code>DEFLIS</code>, both of which are. And also, because <code>PUT</code> would have been very easy for the Lisp 1.5 implementers to implement, if it had been relevant to their working environment. And I shall implement property list as flat lists of interleaved indicator symbols and values, even with that nonsense 77777<sub>8</sub> as a prefix, because now I know (or think I know) that it was a bodge, it seems right in the spirit of historical reconstruction to reconstruct the bodge.</p></div></div></div></body></html>