Classic Computer Magazine Archive CREATIVE COMPUTING VOL. 9, NO. 11 / NOVEMBER 1983 / PAGE 69

Lisp for the Atari. (evaluation) Ken Litkowski.

Datasoft has generally selected well in deciding what functions to incorporate in its implementation of Lisp. If you are familiar with Lisp and wish to invest a significant amount of money, what follows is essential to knowing what to expect. The manual assumes knowledge of Lisp, but Datasoft provides a textbook (Lisp, by P.H. Winston and B.K.P. Horn, Addison-Wesley Publishing Co., Reading MA, 1981), for those who want to learn.

Be forewarned that you will spend a great deal of time in learning, since this is a language unlike anything else you have experienced. General Comments

There are two principal dialects of Lisp, Maclisp, and Interlisp. The manual claims that Atari Interlisp is a subset of standard Interlisp. Except for the use of DEFINEQ instead of DEFUN to define functions, you will not even notice. So little is implemented that the differences between the two dialects are of little consequence. Since the textbook uses Maclisp, a Maclisp emulator was included on the disk to enable you to work the exercises. However, several of the functions in the emulator are flawed, so you may have trouble obtaining the results in the textbook.

An entire programming environment for Lisp may use 150K; in this implementation, only 32K is used, leaving 16K for user programs. This is a significant limitation, although you should remember that, since data and programs are represented in the same way, programs can be stored on disk and called in as data and executed. This is the only way to proceed, given the memory limitations of the package. It requires a great deal of ingenuity, so you must be prepared to cope with the movement of data and programs between memory and disk to make effective use of the system. Relatively few functions have been implemented here. Thus, the full power of Lisp will not be immediately available to the user. However, since all Lisp functions can be written in Lisp, any needed function can be created. Mathematical Functions

Atari Interlisp, like Atari Basic, does not distinguish between fixed and floating point numbers. Only the following arithmetic functions are implemented: + (equivalent to the usual PLUS, except that only two arguments are permitted), * (TIMES, again only two arguments), /(QUOTIENT), SUB (DIFFERENCE), EXP, LOG, and INT. The following standard Lisp functions are not implenented: ABS, ADD1, EXPT, FIX, FLOAT, MAX, MIN, MINUS, REMAINDER, SORT, and SUB1. List Processing Functions

For the most part, the elementary functions seem to have been implemented exactly as required by any dialect of Lisp. This is essential, since it is from these functions that everything else grows. The following functions have been implemented: SET, SETQ, QUOTE (including '), EVAL, CAR, CDR, CONS, LIST, APPEND, LENGTH, and LAST. The dotted pair notation is supported (and is effectively used in disk operations). Composite CARS and CDRS are not implemented, but similar functions are easily created.

The more sophisticated list processing functions do not receive quite the same treatment and can pose some problems. Atari Interlisp has the basic "surgical" functions RPLACA and RPLACD, but lacks DELETE, NCONC, SUBST, PUTPROP (or PUT), GET, REMPROP, and REVERSE. These latter functions are provided in the Maclisp emulator, but are not implemented there with care. PUTPROP and NCONC will not operate in the ways expected, so they must be modified by the user to obtain the expected effect. (I modified PUTPROP, REMPROP, and GET so they would create and operate on association lists; thus, it was useful that they were not system functions.)

Atari Interlisp supports ASSOC, but not the STORE and ARRAY functions. However, it does provide a function @ which returns the nth CDR of a list--a useful function for array-like processing. In addition, the functions UNPACK and PACK are provided for exploding and concatenating atoms. However, PACK ignores numbers and eliminates them from a concatenation. Predicate Functions

Atari Interlisp contains several predicate functions, but falls quite short of providing the variety that might be found in standard implementations. The following functions are implemented: # (equivalent to NUMBERP), >(GREATERP), EQ, ATOM, MEMBER, AND and OR. Curiously, and Somewhat disconcertingly, MEMBER does not operate on lists of numbers, so you cannot determine, for example, whether 10 is a member of the set (4 10 12).

Some relatively standard functions that are not supported include BOUNDP, EQUAL, LESSP, MINUSP, NOT, NULL, and ZEROP. A version of EQUAL is provided in several of the sample programs. Not and NULL are equivalent to (EQ X), where the function determines whether X is equal to NIL. Function-Writing Functions

The elements necessary to write new functions (COND, PROG, GO, RETURN, and PROGN), all of which seem to be implemented in their expected form are provided. To write new functions, the Interlisp forms of DEFINEQ and DEFINE are used, instead of the DEFUN of Maclisp. Atari Interlisp supports LAMBDA, NLAMBDA, and MACRO expressions (equivalent to the EXPR, FEXPR, and MACRO forms of Maclisp). The supplied Maclisp emulator makes it possible to use DEFUN forms, except that only one expression is allowed in the body of the function definition.

Using DEFINEQ to write new functions should pose no canceptual difficulties. However, writing such functions does present some practical problems. On the Atari, the length of a function is limited to one logical line--120 characters. To get around this, you can define a function in steps, pressing the RETURN key before entering the final right parenthesis of the definition. The system will thus digest what it has been given and await the entry of further information. Once a definition has been entered in this form, however, it is virtually impossible to alter it. You can retrieve the function definition using GETD, but you cannot modify it by changing an errant portion of the function. The function must be entered from the beginning.

Fortunately, an editing package is provided as one of the sample programs. This package is more than a sample; rather, it is essential for using this system. Although the editing package does not contain all the sophistication that might be found in a major installation, it provides 2j commands, which are quite adequate.

The manual gives some detailed examples of how to use the editor, but does not sufficiently emphasize its importance. The editor takes up some 7K of the 16K available to the user. As a result, you must usually create functions, store them on disk, erase all user-defined functions, reenter the stored functions (without the editor), and then execute them. Functions with Function Arguments

In addition to the EVAL function, Atari Interlisp implements the APPLY* function. However, none of the composite mapping functions are implemented. MAPCAR and FUNCALL are provided in the Maclisp emulator, but they are designed to take only one set of arguments. This somewhat defeats the purpose of such functions. Input and Output Functions

Atari Interlisp provides a sufficient number of read and print functions (READ, READA, READC, PRINT, PRIN1, PRIN2, TERPRI) to provide you with whatever you need. These functions might differ slightly from what you are accustomed to, but the differences should pose no problem. Several additional functions are implemented to account for the peculiarities of the Atari. These include LOAD, SAVE, OPEN, CLOSE, IN#, PR#, PINT, and NOTE. Each of these functions is supposed to operate like its counterpart in Atari Basic, but such is not quite the case. The manual poorly documents these functions and the differences, leading to some aggravation. For example, I found that I could not save a list directly; instead, I had to create another list containing the name of the list I wanted to save and then save the top list. Error Handling Procedures

Only a few error types are recognized by the system, for example, encountering an undefined function or an atomic expression when a list is expected. When such errors do occur, control is passed to an error handler, which first displays the error type and the expression which caused the error. Once in the error handler, there are four options: 1) exist from the error handler, thus aborting the current evaluation thread; 2) perform any function which would normally be available (including examining the values of any variables in the current evaluation thread); 3) examine, using the function BAKTRACE, the sequence of evaluation which led to the error; 4) continue the evaluation thread by providing a value for the expression which caused the error. A problem occurs in using BAKTRACE when the sequence of functions leading to the error is longer than can be displayed; the evaluation thread nearest the error condition is lost from view, so the benefits of BAKTRACE are lost.

Atari Interlisp provides only one debugging function (BREAK), which prints a message and then passes control to the error handler. An ongoing evaluation can be halted by pressing the control key and the letter B; doing so also passes control to the error handler. No other tracing or step function is provided. System Functions.

To me, the greatest deficiency of Atari Interlisp is the absence of any capability for examining or altering what the system is doing. Some insignificant functions are provided, but these are not sufficient. OBLIST lists all currently defined (system and user) atoms (including functions). NEW reinitializes the system by deleting all user-defined expressions; this cannot be done selectively. MEM returns the number of unused bytes of memory and is the means by which a garbage collection is forced.

PEEK and POKE enable you to examine and to change the contents of any memory location. However, you are not told what is in memory, except for a very few specific locations. Neither are you told what part of Atari's OS and DOS variable are retained, nor are you given a decent memory map. Further, no provision has been made for calling or constructing machine language subroutines.

Memory allocations are maade once and for all, so it is not possible to optimize the use of an already limited memory. Even the information necessary for optimization, e.g., detailed memory maps, how the system makes assignments, and how memory is being used, is not provided. Atari-Specific Functions

Finally, Atari Interlisp implements functions which pertain to the specific characteristics of the Atari computer. These functions, including COL (to set a color register, equivalent to the Atari Basic command COLOR), DRAW, GR (for GRAPHICS), PLOT, SETCOL (for SETCOLOR), SOUND, STICK, and STRIG, are all essentially equivalent to their Basic counterparts. Summary

For the most part, Atari Interlisp is a well-designed system. The functions which have been implemented seem to be the most essential ones. I experienced no significant surprises in the operation of the system, and the documentation, though limited, is reasonable, except for the problems noted above.

I have been able to implement and develop complex augmented transition network grammars, even though they are painful and embarrassingly slow.

If you know Lisp, I think the comments above should enable you to decide if Atari Interlisp will meet your needs. If you don't know Lisp, this would be a fairly expensive way to learn; other, less expensive, although perhaps more limited implementations may be available.

If you already own the package and are interested in extending the capabilities of Atari Interlisp, I am willing to serve as a clearinghouse for information regarding the operation of the system and for any system utility functions. This system should not be permitted to languish. We will all benefit if we collaborate to increase its power.

Products: Interlisp (computer program language)