.page The rest of this chapter explains more of the details of the Lisp Machine Lisp dialect. This section is also suitable for the Maclisp user, as it goes into detail about important differences between the dialects. Those Maclisp users who have skipped the previous sections should definitely read this one.
2.1 Data Types
This section enumerates the various different types of objects in Lisp Machine Lisp. The types explained below include symbols, conses, various types of numbers, two kinds of compiled code object, locatives, arrays, stacks, and closures. With each is given the associated symbolic name, which is returned by the function data-type (LINK:(data-type-fun)).

A symbol (these are sometimes called "atoms" or "atomic symbols" by other texts) has a print name , a binding , a definition , a property list , and a package . The print name is a string, which may be obtained by the function get-pname (LINK:(get-pname-fun)). This string serves as the printed representation (see LINK:(printer)) of the symbol. The binding (sometimes also called the "value") may be any object. It is also referred to sometimes as the "contents of the value cell", since internally every symbol has a cell called the value cell which holds the binding. It is accessed by the symeval function (LINK:(symeval-fun)), and updated by the set function (LINK:(set-fun)). (That is, given a symbol, you use symeval to find out what its binding is, and use set to change its binding.) The definition may also be any Lisp object. It is also referred to as the "contents of the function cell", since internally every symbol has a cell called the function cell which holds the definition. The definition can be accessed by the fsymeval function (LINK:(fsymeval-fun)), and updated with fset (LINK:(fset-fun)). The property list is a list of an even number of elements; it can be accessed directly by plist (LINK:(plist-fun)), and updated directly by setplist (LINK:(setplist-fun)), although usually the functions get , putprop , and remprop (LINK:(get-fun)) are used. The property list is used to associate any number of additional attributes with a symbol--attributes not used frequently enough to deserve their cells as the value and definition do. Symbols also have a package cell, which indicates which "package" of names the symbol belongs to. This is explained further in the section on packages and can be disregarded by the casual user. The primitive function for creating symbols is make-symbol (LINK:(make-symbol-fun)) (currently named make-atom ), although most symbols are created by read , intern , or fasload (who call make-symbol themselves.) A cons is an object that cares about two other objects, arbitrarily named the car and the cdr . These objects can be accessed with car and cdr (LINK:(car-fun)), and updated with rplaca and rplacd (LINK:(rplaca-fun)). The primitive function for creating conses is cons (LINK:(cons-fun)). There are several kinds of numbers in Lisp Machine Lisp. Fixnums represent integers in the range of -2^23 to 2^23-1. Bignums represent integers of arbitrary size, with more overhead than fixnums. The system automatically converts between fixnums and bignums as required. Flonums are floating-point numbers. Small-flonums are another kind of floating-point numbers, with less range and precision, but less computational overhead. Other types of numbers are likely to be added in the future. See this link for full details.

The usual form of compiled code is a Lisp object called a "Function Entry Frame" or "FEF". A FEF contains the code for one function. This is analogous to what Maclisp calls a "subr pointer". FEFs are produced by the Lisp Compiler (this link), and are usually found as the definitions of symbols. The printed representation of a FEF includes its name, so that it can be identified. Another Lisp object which represents executable code is a "micro-code entry". These are the microcoded primitive functions of the Lisp system, and user functions compiled into microcode. About the only useful thing to do with one of these objects is to apply it to arguments. However, some functions are provided for examining such objects, for user convenience. See arglist (LINK:(arglist-fun)), args-info (LINK:(args-info-fun)), describe (LINK:(describe-fun)), and disassemble (LINK:(disassemble-fun)). A locative (see this link) is a kind of a pointer to a single cell anywhere in the system. The contents of this cell can be accessed by either car or cdr (both do the same thing for a locative) (see LINK:(car-fun)) and updated by either rplaca or rplacd (see LINK:(rplaca-fun)). An array (see LINK:(array)) is a set of cells indexed by a tuple of integer subscripts. The contents of cells may be accessed and changed individually. There are several types of arrays. Some have cells which may contain any object, while others (numeric arrays) may only contain small positive numbers. Strings are a type of array; the elements are 8-bit positive numbers which encode characters.

2.2 Lambda Lists

Note: the examples in this section are examples of lambda-lists, not of Lisp forms! A lambda-expression is the form of a user-defined function in Lisp. It looks like (lambda lambda-list SAIL. body) . The body may be any number of forms. In Maclisp and Lisp 1.5, the lambda-list (also called a bound-variable list ) is simply a list of symbols (which act like formal parameters in some other languages). When the lambda-expression is applied to its arguments (which act like actual parameters in other languages), the symbols are bound to the arguments, and the forms of the body are evaluated sequentially; the result of the last of these evaluations is returned. If the number of arguments is not the same as the length of the lambda-list, an error is generated. In Lisp Machine Lisp the same simple lambda-lists may be used, but there are additional features accessible via certain keywords (which start with & ) and by using lists as elements of the lambda-list. The principle weakness of the simple scheme is that any function must only take a certain, fixed number of arguments. As we know, many very useful functions, such as list , append , + , and so on, may take a varying number of arguments. Maclisp solved this problem by the use of lexpr s and lsubr s, which were somewhat inelegant since the parameters had to be referred to by numbers instead of names (e.g. (arg 3) ). (For compatibility reasons, Lisp Machine Lisp supports lexpr s, but they should not be used in new programs). In general, a function in Lisp Machine Lisp has zero or more required parameters, followed by zero or more optional parameters, followed by zero or one rest parameter. This means that the caller must provide enough arguments so that each of the required parameters gets bound, but he may provide some extra arguments for each of the optional parameters. Also, if there is a rest parameter, he can provide as many extra arguments as he wants, and the rest parameter will be bound to a list of all these extras. Also, optional parameters may have a default-form , which is a form to be evaluated to produce the default argument if none is supplied. Here is the exact explanation of how this all works. When apply matches up the arguments with the parameters, it follows the following algorithm: The first required parameter is bound to the first argument. apply continues to bind successive required parameters to the successive arguments. If, during this process, there are no arguments left but there are still some required parameters which have not been bound yet, then an error is caused ("too few arguments"). Next, after all required parameters are handled, apply continues with the optional parameters, binding each argument to each successive parameter. If, during this process, there are no arguments left, each remaining optional parameter's default-form is evaluated, and the parameter is bound to it. This is done one parameter at a time; that is, first one default-form is evaluated, and then the parameter is bound to it, then the next default-form is evaluated, and so on. This allows the default for an argument to depend on the previous argument. Finally, if there is no rest parameter and there are no remaining arguments, we are finished. If there is no rest parameter but there are still some arguments remaining, an error is caused ("too many arguments"). But if there is a rest parameter, it is bound to a list of all of the remaining arguments. (If there are no remaining arguments, it gets bound to nil .) The way you express which parameters are required, optional, and rest is by means of specially recognized symbols, which are called &-keywords , in the lambda-list. All such symbols' print names begin with the character "& ". A list of all such symbols is the value of the symbol lambda-list-keywords . The keywords used here are &optional and &rest . The way they are used is best explained by means of examples; the following are typical lambda-lists, followed by descriptions of which parameters are required, optional, and rest.
(a b c)a , b , and c are all required. This function must be passed three arguments.
(a b &optional c)
a and b are required, c is optional. The function may be passed either two or three arguments.
(&optional a b c)
a , b , and c are all optional. The function may be passed any number of arguments between zero and three, inclusively.
(&rest a)a is a rest parameter. The function may be passed any number of arguments.
(a b &optional c d &rest e)
a and b are required, c and d are optional, and e is rest. The function may be passed two or more arguments.
In all of the cases above, the default-forms for each parameter were nil . To specify your own default forms, instead of putting a symbol as the element of a lambda-list, put in a list whose first element is the symbol (the parameter itself) and whose second element is the default-form. For example:
(a &optional (b 3))
The default-form for b is 3 . a is a required parameter, and so it doesn't have a default form.
(&optional (a 'foo) b (c (symeval a)) &rest d)
a 's default-form is 'foo , b 's is nil , and c 's is (symeval a) . Note that if the function whose lambda-list this is were called on no arguments, a would be bound to the symbol foo , and c would be bound to the binding of the symbol foo ; this illustrates the fact that each variable is bound immediately after its default-form is evaluated, and so later default-forms may take advantage of earlier parameters in the lambda-list. b and d would be bound to nil .
It is also possible to include, in the lambda-list, some other symbols which are bound to the values of their default-forms upon entry to the function. These are not parameters, and they are never bound to arguments; they are like "prog variables". To include such symbols, put them after any parameters, preceeded by the & -keyword &aux . Examples:
(a &optional b &rest c &aux d (e 5) (f (cons a e)))
d , e , and f are bound, when the function is called, to nil , 5 , and a cons of the first argument and 5.
Note that aux-variables are bound sequentially rather than in parallel. It is important to realize that the list of arguments to which a rest-parameter is bound is set up in whatever way is most efficiently implemented, rather than in the way that is most convenient for the function receiving the arguments. It is guaranteed neither to be a "real" list, nor to be a temporary object which may be freely modified. Sometimes the rest-args list is stored in the function-calling stack, and loses its validity when the function returns; if a rest-argument is to be returned or made part of permanent list-structure, it must first be copied (see append ). The system will not detect the error of omitting to copy a rest-argument; you will simply find that you have a value which seems to change behind your back. At other times the rest-args list will be an argument that was given to apply ; therefore it is not safe to rplaca this list as you may modify permanent data structure. An attempt to rplacd a rest-args list will be unsafe in this case, while in the first case it would cause an error.