Further documentation and research around property lists

This commit is contained in:
Simon Brooke 2023-04-04 10:11:46 +01:00
parent 481c11ddf2
commit 52c514c43b
3 changed files with 151 additions and 162 deletions

7
doc/further_reading.md Normal file
View file

@ -0,0 +1,7 @@
# Further Reading
1. [CODING for the MIT-IBM 704 COMPUTER, October 1957](http://bitsavers.org/pdf/mit/computer_center/Coding_for_the_MIT-IBM_704_Computer_Oct57.pdf)
2. [MIT AI Memo 1, John McCarthy, September 1958](https://www.softwarepreservation.org/projects/LISP/MIT/AIM-001.pdf)
3. [Lisp 1 Programmer's Manual, Phyllis Fox, March 1960](https://bitsavers.org/pdf/mit/rle_lisp/LISP_I_Programmers_Manual_Mar60.pdf)
4. [Lisp 1.5 Programmer's Manual, Michael I. Levin, August 1962](https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf#page=81)
4. [Early LISP History (1956 - 1959)](https://dl.acm.org/doi/pdf/10.1145/800055.802047#page=3)

View file

@ -1626,19 +1626,13 @@ ables bound outside of the errorset have not been altered by using cset or set,
damage has been done by pseudo-functions, it may be possible to continue computation damage has been done by pseudo-functions, it may be possible to continue computation
in a different direction when one path results in an error. in a different direction when one path results in an error.
``` ## VII. LIST STRUCTURES
VII. LIST STRUCTURES
In other sections of this manual, lists have been discussed by using the LISP input-
output language. In this section, we discuss the representation of lists inside the com-
puter, the nature of property lists of atomic symbols, representation of numbers, and
the garbage collector.
```
7. 1 Representation of List Structure In other sections of this manual, lists have been discussed by using the LISP input-output language. In this section, we discuss the representation of lists inside the computer, the nature of property lists of atomic symbols, representation of numbers, and the garbage collector.
Lists are not stored in the computer as sequences of BCD characters, but as struc-
tural forms built out of computer words as parts of trees. ### 7.1 Representation of List Structure
In representing list structure, a computer word will be depicted as a rectangle
divided into two sections, the address and decrement. Lists are not stored in the computer as sequences of BCD characters, but as structural forms built out of computer words as parts of trees. In representing list structure, a computer word will be depicted as a rectangle divided into two sections, the address and decrement.
add. I dec. add. I dec.
@ -1660,16 +1654,14 @@ in the decrement.
Following are some diagrammed S-expressions, shown as they would appear in the Following are some diagrammed S-expressions, shown as they would appear in the
computer. It is convenient to indicate NIL by -- - -- - instead of -- -- -F]. computer. It is convenient to indicate NIL by -- - -- - instead of -- -- -F].
```
It is possible for lists to make use of common subexpressions. ((M. N) X (M. N)) It is possible for lists to make use of common subexpressions. ((M. N) X (M. N))
could also be represented as could also be represented as
```
```
Circular lists are ordinarily not permitted. They may not be read in; however, they Circular lists are ordinarily not permitted. They may not be read in; however, they
can occur inside the computer as the result of computations involving certain functions. can occur inside the computer as the result of computations involving certain functions.
Their printed representation is infinite in length. For example, the structure Their printed representation is infinite in length. For example, the structure
```
``` ```
will print as (A B C A B C A. .. will print as (A B C A B C A. ..
@ -1689,9 +1681,7 @@ The advantages of list structures for the storage of symbolic expressions are:
1. The size and even the number of expressions with which the program will have 1. The size and even the number of expressions with which the program will have
to deal cannot be predicted in advance. Therefore, it is difficult to arrange blocks of to deal cannot be predicted in advance. Therefore, it is difficult to arrange blocks of
``` <a name=="page 37">page 37</a>
37
```
storage of fixed length to contain them. storage of fixed length to contain them.
@ -1702,7 +1692,8 @@ available.
3. An expression that occurs as a subexpression of several expressions need be 3. An expression that occurs as a subexpression of several expressions need be
represented in storage only once, represented in storage only once,
7.2 Construction of List Structure ### 7.2 Construction of List Structure
The following simple example has been included to illustrate the exact construction The following simple example has been included to illustrate the exact construction
of list structures. Two types of list structures are shown, and a function for deriving of list structures. Two types of list structures are shown, and a function for deriving
one from the other is given in LISP. one from the other is given in LISP.
@ -1740,26 +1731,27 @@ So rnltgrp applied to the list P1 takes each threesome, (X Y Z), in turn and app
to it to put it in the new form, (X (Y Z)) until the list P1 has been exhausted and the new to it to put it in the new form, (X (Y Z)) until the list P1 has been exhausted and the new
list P2 achieved. list P2 achieved.
7.3 Property Lists ### 7.3 Property Lists
In other sections, atomic symbols have been considered only as pointers. In this In other sections, atomic symbols have been considered only as pointers. In this
section the property lists of atomic symbols that begin at the appointed locations are section the property lists of atomic symbols that begin at the appointed locations are
described. described.
Every atomic symbol has a property list. When an atomic symbol is read in for Every atomic symbol has a property list. When an atomic symbol is read in for
the first time, a property list is created for it. the first time, a property list is created for it.
A property list is characterized by having the special constant 777778 (i. e., minus 1) A property list is characterized by having the special constant 777778 (i. e., minus 1)
as the first element of the list. The rest of the list contains various properties of the 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 atomic symbol which is called its atomic symbol. Each property is preceded by an atomic symbol which is called its
indicator. Some of the indicators are: indicator. Some of the indicators are:
``` | Indicator | Description |
PNAME - the BCD print name of the atomic symbol for input-output use. | --------- | ------------------------------------------------------------ |
EXPR - S-expression defining a function whose name is the atomic symbol | PNAME | the BCD print name of the atomic symbol for input-output use. |
on whose property list the EXPR appears. | EXPR | S-expression defining a function whose name is the atomic symbol on whose property list the EXPR appears. |
SUBR - Function defined by a machine language subroutine. | SUBR | Function defined by a machine language subroutine. |
APVAL - Permanent value for the atomic symbol considered as a variable. | APVAL | Permanent value for the atomic symbol considered as a variable. |
```
```
The atomic symbol NIL has two things on its property list - its PNAME, and an The atomic symbol NIL has two things on its property list - its PNAME, and an
APVAL that gives it a value of NIL. Its property list looks like this: APVAL that gives it a value of NIL. Its property list looks like this:
``` ```
@ -1805,14 +1797,13 @@ TXL 37721,, 2 1
``` ```
The indicator EXPR points to an S-expression defining a function. The function define The indicator EXPR points to an S-expression defining a function. The function define
puts EXPR1s on property lists. After defining ff, its property list would look like this puts EXPR1s on property lists. After defining ff, its property list would look like this
```
-1 I -1 I
LAMBDA I LAMBDA I
The function get[x;i] can be used to find a property of x whose indicator is i. The The function get[x;i] can be used to find a property of x whose indicator is i. The
value of get[~~;~G~] would be (LAMBDA (X) (COW... value of get[X; G] would be (LAMBDA (X) (COW...
A property with its indicator can be removed by remprop[x;i]. A property with its indicator can be removed by remprop[x;i].
The function deflist[x;i] can be used to put any indicator on a property list. The The function deflist[x;i] can be used to put any indicator on a property list. The
first argument is a list of pairs as for define, the second argument is the indicator to first argument is a list of pairs as for define, the second argument is the indicator to
@ -1826,45 +1817,38 @@ and what type it is, and a pointer to the number itself in the decrement of this
Unlike atomic symbols, numbers are not stored uniquely. Unlike atomic symbols, numbers are not stored uniquely.
For example, the decimal number 15 is represented as follows: For example, the decimal number 15 is represented as follows:
7.4 List Structure Operators ### 7.4 List Structure Operators
The theory of recursive functions developed in Section I will be referred to as elementary LISP. Although this language is universal in terms of computable functions of symbolic expressions, it is not convenient as a programming system without additional tools to increase its power.
In particular, elementary LISP has no ability to modify list structure. The only basic function that affects list structure is `cons`, and this does not change existing lists, but creates new lists. Functions written in pure LISP such as `subst` do not actually modify their arguments, but make the modifications while copying the original.
The theory of recursive functions developed in Section I will be referred to as ele-
mentary LISP. Although this language is universal in terms of computable functions of
symbolic expressions, it is not convenient as a programming system without additional
tools to increase its power.
In particular, elementary LISP has no ability to modify list structure. The only
basic function that affects list structure is cons, and this does not change existing lists,
but creates new lists. Functions written in pure LISP such as subst do not actually mod-
ify their arguments, but make the modifications while copying the original.
LISP is made general in terms of list structure by means of the basic list operators LISP is made general in terms of list structure by means of the basic list operators
rplaca and rplacd. These operators can be used to replace the address or decrement `rplaca` and `rplacd`. These operators can be used to replace the address or decrement
or any word in a list. They are used for their effect, as well as for their value, and or any word in a list. They are used for their effect, as well as for their value, and
are called pseudo-functions. are called pseudo-functions.
rplaca[x;y] replaces the address of x with y. Its value is x, but x is something
different from what it was before. In terms of value, rplaca can be described by the `rplaca[x;y]` replaces the address of `x` with `y`. Its value is `x`, but `x` is something different from what it was before. In terms of value, rplaca can be described by the equation
equation
rpla~a[x;~] = c~ns[~;cdr[x]] rpla~a[x;~] = c~ns[~;cdr[x]]
But the effect is quite different: there is no cons involved and a new word is not created. But the effect is quite different: there is no cons involved and a new word is not created.
rplacd[x;y] replaces the decrement of x with y.
`rplacd[x;y]` replaces the decrement of `x` with `y`.
These operators must be used with caution. They can permanently alter existing These operators must be used with caution. They can permanently alter existing
definitions and other basic memory. They can be used to create circular lists, which definitions and other basic memory. They can be used to create circular lists, which
can cause infinite printing, and look infinite to functions that search, such as equal and can cause infinite printing, and look infinite to functions that search, such as `equal` and
subst. `subst`.
As an example, consider the function mltgrp of section 7.2. This is a list-altering
function that alters a copy of its argument. The subfunction - grp rearranges a subgroup As an example, consider the function mltgrp of section 7.2. This is a list-altering function that alters a copy of its argument. The subfunction - grp rearranges a subgroup
The original function does this by creating new list structures, and uses four cons's. Because there are only three words in the original, at least one cons is necessary, but
```
The original function does this by creating new list structures, and uses four cons's.
Because there are only three words in the original, at leaSt one cons is necessary, but
```
- grp can be rewritten by using rplaca and rplacd. - grp can be rewritten by using rplaca and rplacd.
The modification is The modification is
``` The new word is created by cons[cadr[x];cddr[x]]. A pointer to it is provided by rplaca[cdr[x];cons[cadr[x];cddr[x]]].
The new word is created by cons[cadr[x];cddr[x]]. A pointer to it is provided by
rplaca[cdr[x];cons[cadr[x];cddr[x]]].
The other modification is to break the pointer from the second to the third word. The other modification is to break the pointer from the second to the third word.
This is done by rplacd[cdr[x];~l~]. This is done by rplacd[cdr[x];~l~].
pgrp - is now defined as pgrp - is now defined as
@ -1876,64 +1860,29 @@ pmltgrp[l] = [null[l] -. NIL;
T -- ~rog2[~g~~[car[~Il~~~~tgr~[cdr[~1111 T -- ~rog2[~g~~[car[~Il~~~~tgr~[cdr[~1111
prog2 is a function that evaluates its two arguments. Its value is the second argument. prog2 is a function that evaluates its two arguments. Its value is the second argument.
The value of pmltgrp is NIL. pgrp - and - pmltgrp are pseudo-functions. The value of pmltgrp is NIL. pgrp - and - pmltgrp are pseudo-functions.
```
```
7.5 The Free-Storage List and the Garbage Collector
```
At any given time only a part of the memory reserved for list structures will actually ### 7.5 The Free-Storage List and the Garbage Collector
be in use for storing S-expressions. The remaining registers are arranged in a single
list called the free-storage list. A certain register, FREE, in the program contains the
location of the first register in this list. When a word is required to form some addi-
tional list structure, the first word on the free-storage list is taken and the number in
register FREE is changed to become the location of the second word on the free-storage
``` At any given time only a part of the memory reserved for list structures will actually be in use for storing S-expressions. The remaining registers are arranged in a single list called the free-storage list. A certain register, FREE, in the program contains the location of the first register in this list. When a word is required to form some additional list structure, the first word on the free-storage list is taken and the number in register FREE is changed to become the location of the second word on the free-storage list. No provision need be made for the user to program the return of registers to the free-storage list.
list. No provision need be made for the user to program the return of registers to the
free-storage list.
This return takes place automatically whenever the free -storage list has been
exhausted during the running of a LISP program. The program that retrieves the storage
is called the garbage collector.
Any piece of list structure that is accessible to programs in the machine is consid-
ered an active list and is not touched by the garbage collector. The active lists are
accessible to the program through certain fixed sets of base registers, such as the reg-
isters in the list of atomic symbols, the registers that contain partial results of the
LISP computation in progress, etc. The list structures involved may be arbitrarily
long but each register that is active must be connected to a base register through a car-
cdr - chain of registers. Any register that cannot be so reached is not accessible to any
program and is nonactive; therefore its contents are no longer of interest.
The nonactive, i. e. , inaccessible, registers are reclaimed for the free-storage list
by the garbage collector as follows. First, every active register that can be reached
through a car-cdr chain is marked by setting its sign negative. Whenever a negative
register is reached in a chain during this process, the garbage collector knows that the
rest of the list involving that register has already been marked. Then the garbage col-
lector does a linear sweep of the free-storage area, collecting all registers with a posi-
tive sign into a new free-storage list, and restoring the original signs of the active
registers.
Sometimes list structure points to full words such as BCD print names and numbers.
The garbage collector cannot mark these words because the sign bit may be in use. The
garbage collector must also stop tracing because the pointers in the address and decre-
ment of a full word are not meaningful.
These problems are solved by putting full words in a reserved section of memory
called full-word space. The garbage collector stops tracing as soon as it leaves the
```
--- free-storage space. Marking in full-word space is accomplished by a bit table. This return takes place automatically whenever the free -storage list has been exhausted during the running of a LISP program. The program that retrieves the storage is called the garbage collector.
``` Any piece of list structure that is accessible to programs in the machine is considered an active list and is not touched by the garbage collector. The active lists are accessible to the program through certain fixed sets of base registers, such as the registers in the list of atomic symbols, the registers that contain partial results of the LISP computation in progress, etc. The list structures involved may be arbitrarily long but each register that is active must be connected to a base register through a car-cdr - chain of registers. Any register that cannot be so reached is not accessible to any program and is nonactive; therefore its contents are no longer of interest.
VIII. A COMPLETE LISP PROGRAM - THE WANG ALGORITHM FOR THE
PROPOSITIONAL CALCULUS
```
This section gives an example of a complete collection of LISP function definitions The nonactive, i. e. , inaccessible, registers are reclaimed for the free-storage list by the garbage collector as follows. First, every active register that can be reached through a car-cdr chain is marked by setting its sign negative. Whenever a negative register is reached in a chain during this process, the garbage collector knows that therest of the list involving that register has already been marked. Then the garbage collector does a linear sweep of the free-storage area, collecting all registers with a positive sign into a new free-storage list, and restoring the original signs of the active registers.
which were written to define an algorithm. The program was then run on several test
cases. The algorithm itself is explained, and is then written in M-expressions. The Sometimes list structure points to full words such as BCD print names and numbers. The garbage collector cannot mark these words because the sign bit may be in use. The garbage collector must also stop tracing because the pointers in the address and decrement of a full word are not meaningful.
complete input card deck an'd the printed output of the run are reprinted here.
The Wang Algorithm^1 is a method of deciding whether or not a formula in the prop- These problems are solved by putting full words in a reserved section of memory called full-word space. The garbage collector stops tracing as soon as it leaves the free-storage space. Marking in full-word space is accomplished by a bit table.
oditional calculus is a theorem. The reader will need to know something about the prop-
ositional calculus in order to understand this discussion. ### VIII. A COMPLETE LISP PROGRAM - THE WANG ALGORITHM FOR THE PROPOSITIONAL CALCULUS
We quote from pages 5 and 6 of Wangls paper:
This section gives an example of a complete collection of LISP function definitions which were written to define an algorithm. The program was then run on several test cases. The algorithm itself is explained, and is then written in M-expressions. The complete input card deck and the printed output of the run are reprinted here.
The [Wang Algorithm](https://dl.acm.org/doi/abs/10.1147/rd.41.0002) is a method of deciding whether or not a formula in the propositional calculus is a theorem. The reader will need to know something about the propositional calculus in order to understand this discussion.
We quote from pages 5 and 6 of Wang's paper:
"The propositional calculus (System P) "The propositional calculus (System P)
Since we are concerned with practical feasibility, it is preferable to use more logical Since we are concerned with practical feasibility, it is preferable to use more logical
connectives to begin with when we wish actually to apply the procedure to concrete cases. connectives to begin with when we wish actually to apply the procedure to concrete cases.
@ -1958,13 +1907,11 @@ vinced that these rules are indeed correct. Later on, a proof will be given of t
pleteness, i. e., all intuitively valid sequents are provable, and of their consistency, pleteness, i. e., all intuitively valid sequents are provable, and of their consistency,
i. e. , all provable sequents are intuitively valid. i. e. , all provable sequents are intuitively valid.
```
"PI. Initial rule: if h, 5 are strings of atomic formulae, then h -. 5 is a theorem if "PI. Initial rule: if h, 5 are strings of atomic formulae, then h -. 5 is a theorem if
some atomic formula occurs on both sides of the arrow. some atomic formula occurs on both sides of the arrow.
"In the ten rules listed below, h and 5 are always strings (possibly empty) of atomic "In the ten rules listed below, h and 5 are always strings (possibly empty) of atomic
formulae. As a proof procedure in the usual sense, each proof begins with a finite set formulae. As a proof procedure in the usual sense, each proof begins with a finite set
of cases of P1 and continues with successive consequences obtained by the other rules .I1 of cases of P1 and continues with successive consequences obtained by the other rules .I1
```
1. Wang, Hao. "Toward Mechanical Mathematics," IBM J. Res. Develop., Vo1.4, 1. Wang, Hao. "Toward Mechanical Mathematics," IBM J. Res. Develop., Vo1.4,
No. 1. January 1960. No. 1. January 1960.
@ -2554,30 +2501,14 @@ FIN END OF LISP RUN M948-1207 LEVIN
END OF LISP JOB END OF LISP JOB
``` ```
```
APPENDIX A
```
``` ## APPENDIX A : FUNCTIONS AND CONSTANTS IN THE LISP SYSTEM
FUNCTIONS AND CONSTANTS IN THE LISP SYSTEM
``` This appendix contains all functions available in the LISP System as of August 1962. Each entry contains the name of the object, the property under which it is available (e. g., EXPR, FEXPR, SUBR, FSUBR, or APVAL), whether it is a pseudo-function, functional (function having functions as arguments), or predicate, and in some cases a definition of the function as an M-expression. In the case of APVALts, the value is given.
The LISP Library is a file of BCD cards distributed with the LISP System. It is not intended to be used as input to the computer without being edited first. Have the Library file punched out, and then list the cards. Each Library function is preceded by a title card that must be removed. Some Library entries are in the form of a DEFINE, while some are in the form of an assembly in LAP. Note that some of them have auxiliary functions that must be included.
```
This appendix contains all functions available in the LISP System as of August 1962.
Each entry contains the name of the object, the property under which it is available
(e. g., EXPR, FEXPR, SUBR, FSUBR, or APVAL), whether it is a pseudo-function,
functional (function having functions as arguments), or predicate, and in some cases
a definition of the function as an M-expression. In the case of APVALts, the value is
given.
The LISP Library is a file of BCD cards distributed with the LISP System. It is not
intended to be used as input to the computer without being edited first. Have the Library
file punched out, and then list the cards. Each Library function is preceded by a title
card that must be removed. Some Library entries are in the form of a DEFINE, while
some are in the form of an assembly in LAP. Note that some of them have auxiliary
functions that must be included.
```
```
Elementary Functions Elementary Functions
car - [x] SUBR car - [x] SUBR
cdr - [x] SUBR cdr - [x] SUBR
@ -2678,9 +2609,8 @@ TRUE
TRANSFER IF EQUAL TRANSFER IF EQUAL
OTHERWISE VALUE IS NIL OTHERWISE VALUE IS NIL
VALUE IS *T* VALUE IS *T*
```
equal[^;^] - SUBR predicate equal[x; y] - SUBR predicate
* equal is true if its arguments are the same S-expression, although they do not have * equal is true if its arguments are the same S-expression, although they do not have
to be identical list structure in the computer. It uses 7 eq on the atomic level and is to be identical list structure in the computer. It uses 7 eq on the atomic level and is
@ -2702,32 +2632,28 @@ CLA TRUE
TRA 1,4 TRA 1,4
TRUE OCT 1000000 TRUE OCT 1000000
``` ```
<a name="page58">page 58</a>
* rplaca[x;y] SUBR pseudo-function #### rplaca[x; y] : SUBR pseudo-function
#### rplacd[x; y] : SUBR pseudo-function
```
rplacd[x;y] SUBR pseudo-function
These list operators change list structure and can damage the system memory if not These list operators change list structure and can damage the system memory if not
used properly. See page^41 for a description of usage. used properly. See [page 41](#page41) for a description of usage.
```
``` ### Logical Connectives
Logical Connectives
```
- and[x ;x2... ;xn] : FSUBR predicate #### and[x<sub>1</sub>; x<sub>2</sub>; ... ; x<sub>n</sub>] : FSUBR predicate
```
The arguments of are evaluated in sequence, from left to right, until one is found The arguments of are evaluated in sequence, from left to right, until one is found
that is false, or until the end of the list is reached. The value of & is false or true that is false, or until the end of the list is reached. The value of and is false or true
respectively. respectively.
```
- 0r[x1;x2... ;xn] : FSUBR predicate #### or[x<sub>1</sub>; x<sub>2</sub>; ... ; x<sub>n</sub>] : FSUBR predicate
The arguments of or are evaluated in sequence from left to right, until one is found
that is true, or until the end of the list is reached. The value of 2 is true or The arguments of or are evaluated in sequence from left to right, until one is found that is true, or until the end of the list is reached. The value of or is true or false respectively.
false respectively.
* not [x] SUBR predicate #### not [x]: SUBR predicate
The value of not is true if its argument is false, and false otherwise. The value of not is true if its argument is false, and false otherwise.
@ -2748,24 +2674,21 @@ where each `u` is a name and each `v` is a &lambda;-expression for a function .
> define[x] = deflist[x; EXPR] > define[x] = deflist[x; EXPR]
#### deflist [x; ind] : EXPR pseudo-function
The function `deflist` is a more general defining function. Its first argument is a list of pairs as for define. Its second argument is the indicator that is to be used. After `deflist` 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:
deflist [x; ind] EXPR pseudo-function If `deflist` or `define` is used twice on the same object with the same indicator, the old value will be replaced by the new one.
The function deflist is a more general defining function. Its first argument is a list
of pairs as for define. Its second argument is the indicator that is to be used. After #### attrib[x;e] : SUBR pseudo-function
deflist has been executed with (ui vi) among its first argument, the property list of ui
will begin: The function attrib concatenates its two arguments by changing the last element of its first argument to point to the second argument. Thus it is commonly used to tack something onto the end of a property list. The value of attrib is the second argument.
If deflist or define is used twice on the same object with the same indicator, the old
value will be replaced by the new one.
attrib[x;e] - SUBR pseudo-function
The function attrib concatenates its two arguments by changing the last element of
its first argument to point to the second argument. Thus it is commonly used to tack
something onto the end of a property list. The value of attrib is the second argument.
For example For example
attrib[~~; (EXPR (LAMBDA (X) (COND ((ATOM X) X) (T (FF (CAR x))))))] attrib[~~; (EXPR (LAMBDA (X) (COND ((ATOM X) X) (T (FF (CAR x))))))]
would put EXPR followed by the LAMBDA expression for FF onto the end of the prop- would put EXPR followed by the LAMBDA expression for FF onto the end of the prop-
erty list for FF. erty list for FF.
``` ```
- pr~p[x;~;u] SUBR functional - pr~p[x;~;u] SUBR functional

View file

@ -47,6 +47,22 @@ O14 (read lines O and 1)
Of course, this isn't proof. If `CAR` and `CDR` used here are standard IBM 704 assembler mnemonics -- as I believe they are -- then what is `CONS`? It's used in a syntactically identical way. If it also is an assembler mnemonic, then it's hard to believe that, as legend relates, it is short for 'construct'; on the other hand, if it's a label representing an entry point into a subroutine, then why should `CAR` and `CDR` not also be labels? Of course, this isn't proof. If `CAR` and `CDR` used here are standard IBM 704 assembler mnemonics -- as I believe they are -- then what is `CONS`? It's used in a syntactically identical way. If it also is an assembler mnemonic, then it's hard to believe that, as legend relates, it is short for 'construct'; on the other hand, if it's a label representing an entry point into a subroutine, then why should `CAR` and `CDR` not also be labels?
-----
**Edited 3<sup>rd</sup> April to add:** I've 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 [CODING for the MIT-IBM 704 COMPUTER](http://bitsavers.org/pdf/mit/computer_center/Coding_for_the_MIT-IBM_704_Computer_Oct57.pdf), 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 isn't right. But the names are correct. Consider [this excerpt](http://bitsavers.org/pdf/mit/computer_center/Coding_for_the_MIT-IBM_704_Computer_Oct57.pdf#page=145) :
> 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.
This doesn't prove there were individual machine instructions with the mnemonics `CAR` and `CDR`; in fact, I'm going to say with some confidence that there were not, by reference to [the table of instructions](http://bitsavers.org/pdf/mit/computer_center/Coding_for_the_MIT-IBM_704_Computer_Oct57.pdf#page=170) 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 `CAR` and `CDR` are not included.
So it seems probable that `CAR` and `CDR` 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.
And, going further down the rabbit hole, [there's this](https://dl.acm.org/doi/pdf/10.1145/800055.802047#page=3). 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.
> 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
-----
I think that the answer has to be that if `CAR` and `CDR` 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 `FRST` and `REST`, as in more modern Lisps, then something like `P1` and `P2`. `CAR` and `CDR` 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. I think that the answer has to be that if `CAR` and `CDR` 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 `FRST` and `REST`, as in more modern Lisps, then something like `P1` and `P2`. `CAR` and `CDR` 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.
Let's be clear, here: when `CAR` and `CDR` 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. Let's be clear, here: when `CAR` and `CDR` 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.
@ -262,6 +278,49 @@ Lisp 1.5 doesn't have `PUT`, `PUTPROP` or `DEFUN` because setting properties ind
----- -----
## Deeper delving
After writing, and publishing, this essay, I went on procrastinating, which is what I do when I'm sure I'm 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 team's first ever memo, written by John McCarthy in September 1958. And in that, I find this:
> 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.
>
> | Letter | Description |
> | ---- | ---------------------------- |
> | w | the whole word |
> | p | the prefix (bits s, 1, 2) |
> | i | the indicator (bits 1 and 2) |
> | s | the sign bit |
> | d | the decrement (bits 3-17) |
> | t | the tag (bits 18-20) |
> | a | the address (bits 21-35) |
In the discussion of functions which access properties on [page 58 of the Lisp 1.5 programmer's manual](https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf#page=66), the word 'indicator' is used in preference to 'symbol' for the name of a property: for example
> The function `deflist` is a more general defining function. Its first argument is a list of pairs as for define. Its second argument is the *indicator* that is to be used. After `deflist` 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:
>
> If `deflist` or `define` is used twice on the same object with the same *indicator*, the old value will be replaced by the new one.
(my emphasis).
That use of 'indicator' has been nagging at me for a week. It looks like a term of art. If it's just an ordinary atomic symbol, why isn't it called a symbol?
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 what's been worrying and surprising me is that property lists are shown in the manual as flat lists. Eureka? I don't *think* so.
The reason I don't 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, `APVAL`, `EXPR`, `FEXPR`, `SUBR` and `FSUBR`.
Furthermore, on [page 39](https://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf#page=47), we have:
> 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 *atomic symbol* which is called its
> *indicator*.
(again, my emphasis)
But I'm 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.
-----
So what this is about is I've spent most of a whole day procrastinating, because I'm not exactly sure how I'm going to make the change I've got to make. Versions of Beowulf up to and including 0.2.1 used the naive understanding of the architecture; version 0.3.0 *should* use the corrected version. But before it can, I need to be reasonably confident that I understand what the correct solution is. So what this is about is I've spent most of a whole day procrastinating, because I'm not exactly sure how I'm going to make the change I've got to make. Versions of Beowulf up to and including 0.2.1 used the naive understanding of the architecture; version 0.3.0 *should* use the corrected version. But before it can, I need to be reasonably confident that I understand what the correct solution is.
I *shall* implement `PUT`, even though it isn't in the spec, because it's a useful building block on which to build `DEFINE` and `DEFLIS`, both of which are. And also, because `PUT` would have been very easy for the Lisp 1.5 implementers to implement, if it had been relevant to their working environment. I *shall* implement `PUT`, even though it isn't in the spec, because it's a useful building block on which to build `DEFINE` and `DEFLIS`, both of which are. And also, because `PUT` 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.