WAITS: Programming in Lisp
Continuing our series about programming on WAITS, this week we'll look at Lisp.
History
Stanford had a version of Lisp on the IBM 7090 and PDP-1 machines used in the first few years of the lab's existence. When they got their PDP-6 they took an early version of Maclisp from MIT, made changes to get it to work with the WAITS system and released it in 1966 in Lisp 1.6. The authors were John Allen, Lynn Quam and Whitfield Diffie (who after leaving SAIL became famous for his work on cryptography).
Lisp 1.6 gained some additional features: as of 1974, the date of the disk image we are using, it had:
- An arbitrary precision fixed point number system.
- An interactive s-expression editor called ALVINE.
- Flexible I/O, including to the teletype and to files.
- A compiler, which reportedly produced code that ran twenty times faster than interpreted code.
- A library to control the III display terminal.
- Debugging and tracing features.
Using interactive Lisp
Start the interpreter with R LISP. By default this will give you 12k
of core which is only enough for trivial programs, to give more core
space add a number representing the core size in kilowords, eg R LISP 48.
It will ask you ALLOC? which if you type Y will allow you to
change sizes of memory buffers; normally just press Enter here. It
will then put you at the * prompt where you can type s-expressions.
Use upper case.
.r lisp ALLOC? *(PLUS 2 2) 4
Note that integers are in octal, so use real numbers for calculations.
*(TIMES 8 3) 30 *(TIMES 8.0 3) 24.0
Typing altmode (the Escape key) will close all open parens, for
example after entering 5 below I pressed Escape, the interpreter printed
$ and the two close parens were supplied automatically.
*(PLUS 10.0 2 (TIMES 6 5$ 42.0
Variables can be set with SETQ and functions defined with DE.
*(SETQ Y 3) 3 *(DE DOUBLE (X) (TIMES X 2)) DOUBLE *(DOUBLE Y) 6
The I/O system can handle multiple channels, but for simple reading
from the terminal you can use READ which will accept a s-expression
as input. PRINT will type out its argument, but you can also just
evaluate a form to display its value.
Programs - collections of functions and other declarations can be
created by editors outside of Lisp and read in to the environment
using DSKIN. For example, (DSKIN (FOO . LSP)) will read in the
file FOO.LSP in your current file area.
TPK in Lisp
Let's demonstrate Lisp by implementing the TPK algorithm in Lisp 1.6. We can use the Lisp 1.5 code for CTSS as a base. In the Lisp 1.5 version, the key function to calculate TPK, √|x| + 5x³, is expressed as
(F (LAMBDA (X) (PLUS (SQRT (ABS X)) (TIMES 5 (EXPT X 3)))))so in Stanford Lisp 1.6 this would be:
(DE F (X)
(PLUS (SQRT (ABS X)) (TIMES 5 (EXPT X 3))))
However, whereas Lisp 1.5 had EXPT but no SQRT or ABS, here
we have ABS but not EXPT or SQRT. We can implement (EXPT X 3)
as a cube function (TIMES X X X) but for SQRT we will need to
resort to the Babylon algorithm we last used in the Essex BCPL
program.
(DE CLOSE (X GUESS)
(LESSP (ABS (DIFFERENCE (TIMES GUESS GUESS) X)) 0.000001))
(DE IMPROVE (X GUESS)
(QUOTIENT (PLUS GUESS (QUOTIENT X GUESS)) 2.0))
(DE BABYLON (X GUESS)
(COND ((CLOSE X GUESS) GUESS)
(T (BABYLON X (IMPROVE X GUESS)))))
(DE SQRT (X)
(BABYLON X (QUOTIENT X 2.0)))This is recursive, so may run out of space for large numbers.
The heart of the program is then:
(DE F (X)
(PLUS (SQRT (ABS X)) (TIMES 5 (CUBE X))))
(DE LIMIT-F (X)
(PROG (RESULT)
(SETQ RESULT (F X))
(RETURN (COND
((GREATERP RESULT 400.0) (QUOTE TOO-LARGE))
(T RESULT)))))
(DE TPK (NUMS)
(MAPCAR (FUNCTION LIMIT-F) (REVERSE NUMS)))
MAPCAR is available so this was slightly simpler to write compared
to Lisp 1.5.
Finally, a driver program doing the I/O:
(DE MAIN ()
(PROG (NUMS)
(PRINT (QUOTE "Please enter 11 numbers in a list"))
(SETQ NUMS (READ))
(PRINT (QUOTE "Results are"))
(RETURN (TPK NUMS))))
To run, we load the file onto the file system using the techniques
discussed in a previous post. When we run Lisp we need to give it some
more core - here 32k just to be sure. We load in the file with DSKIN
and execute the main function.
.r lisp 32 ALLOC? *(DSKIN (TPK.LSP)) CLOSE IMPROVE BABYLON SQRT CUBE F LIMIT-F TPK MAIN FINISHED-LOADING *(MAIN) "Please enter 11 numbers in a list" *(10.0 -1.0 1.0 2.0 3.0 4.0 4.3 4.305 4.303 4.302 4.301) "Results are" (399.88630 TOO-LARGE TOO-LARGE TOO-LARGE 399.60864 322.0 136.73204 41 .414213 6.0000000 -3.9999999 TOO-LARGE)
Further information
The primary manual for Stanford Lisp 1.6 can be found in LISP.WD[S,DOC].
The Computer History Museum Software Preservation Group has a detailed history of Lisp, including a page on Lisp 1.6 with several versions of the above manual in PDF format, and information on versions derived from this.
A simpler introduction to Lisp of this area can be found in Clark Weissman's LISP 1.5 Primer, which is also available at the Lisp history page above.
Questions, corrections, comments
I welcome any questions or comments, and also especially any corrections if I have got something wrong. Please email me at rupert@timereshared.com and I will add it here and update the main text.