Common Lisp the Language, 2nd Edition


next up previous contents index
Next: Top-Level Forms Up: Functions Previous: Named Functions

5.2.2. Lambda-Expressions

A lambda-expression is a list with the following syntax:

(lambda lambda-list . body)

The first element must be the symbol lambda. The second element must be a list. It is called the lambda-list, and specifies names for the parameters of the function. When the function denoted by the lambda-expression is applied to arguments, the arguments are matched with the parameters specified by the lambda-list. The body may then refer to the arguments by using the parameter names. The body consists of any number of forms (possibly zero). These forms are evaluated in sequence, and the results of the last form only are returned as the results of the application (the value nil is returned if there are zero forms in the body). The complete syntax of a lambda-expression is:

(lambda ({var}*
         [&optional {var | (var [initform [svar]])}*]
         [&rest var]
         [&key {var | ({var | (keyword var)} [initform [svar]])}*
                [&allow-other-keys]]
         [&aux {var | (var [initform])}*)]
   [[{declaration}* | documentation-string]]
   {form}*)

Each element of a lambda-list is either a parameter specifier or a lambda-list keyword; lambda-list keywords begin with &. (Note that lambda-list keywords are not keywords in the usual sense; they do not belong to the keyword package. They are ordinary symbols each of whose names begins with an ampersand. This terminology is unfortunately confusing but is retained for historical reasons.)

old_change_begin
In all cases a var or svar must be a symbol, the name of a variable; each keyword must be a keyword symbol, such as :start. An initform may be any form.
old_change_end

change_begin
X3J13 voted in March 1988 (KEYWORD-ARGUMENT-NAME-PACKAGE)   to allow a keyword in the preceding specification of a lambda-list to be any symbol whatsoever, not just a keyword symbol in the keyword package. See below.
change_end

A lambda-list has five parts, any or all of which may be empty:

When the function represented by the lambda-expression is applied to arguments, the arguments and parameters are processed in order from left to right. In the simplest case, only required parameters are present in the lambda-list; each is specified simply by a name var for the parameter variable. When the function is applied, there must be exactly as many arguments as there are parameters, and each parameter is bound to one argument. Here, and in general, the parameter is bound as a lexical variable unless a declaration has been made that it should be a special binding; see defvar, proclaim, and declare.

In the more general case, if there are n required parameters (n may be zero), there must be at least n arguments, and the required parameters are bound to the first n arguments. The other parameters are then processed using any remaining arguments.

If optional parameters are specified, then each one is processed as follows. If any unprocessed arguments remain, then the parameter variable var is bound to the next remaining argument, just as for a required parameter. If no arguments remain, however, then the initform part of the parameter specifier is evaluated, and the parameter variable is bound to the resulting value (or to nil if no initform appears in the parameter specifier). If another variable name svar appears in the specifier, it is bound to true if an argument was available, and to false if no argument remained (and therefore initform had to be evaluated). The variable svar is called a supplied-p parameter; it is bound not to an argument but to a value indicating whether or not an argument had been supplied for another parameter.

After all optional parameter specifiers have been processed, then there may or may not be a rest parameter. If there is a rest parameter, it is bound to a list of all as-yet-unprocessed arguments. (If no unprocessed arguments remain, the rest parameter is bound to the empty list.) If there is no rest parameter and there are no keyword parameters, then there should be no unprocessed arguments (it is an error if there are).

change_begin
X3J13 voted in January 1989 (REST-LIST-ALLOCATION)   to clarify that if a function has a rest parameter and is called using apply, then the list to which the rest parameter is bound is permitted, but not required, to share top-level list structure with the list that was the last argument to apply. Programmers should be careful about performing side effects on the top-level list structure of a rest parameter.

This was the result of a rather long discussion within X3J13 and the wider Lisp community. To set it in its historical context, I must remark that in Lisp Machine Lisp the list to which a rest parameter was bound had only dynamic extent; this in conjunction with the technique of ``cdr-coding'' permitted a clever stack-allocation technique with very low overhead. However, the early designers of Common Lisp, after a great deal of debate, concluded that it was dangerous for cons cells to have dynamic extent; as an example, the ``obvious'' definition of the function list

(defun list (&rest x) x)

could fail catastrophically. Therefore the first edition simply implied that the list for a rest parameter, like all other lists, would have indefinite extent. This still left open the flip side of the question, namely, Is the list for a rest parameter guaranteed fresh? This is the question addressed by the X3J13 vote. If it is always freshly consed, then it is permissible to destroy it, for example by giving it to nconc. However, the requirement always to cons fresh lists could impose an unacceptable overhead in many implementations. The clarification approved by X3J13 specifies that the programmer may not rely on the list being fresh; if the function was called using apply, there is no way to know where the list came from.
change_end

Next, any keyword parameters are processed. For this purpose the same arguments are processed that would be made into a list for a rest parameter. (Indeed, it is permitted to specify both &rest and &key. In this case the remaining arguments are used for both purposes; that is, all remaining arguments are made into a list for the &rest parameter and are also processed for the &key parameters. This is the only situation in which an argument is used in the processing of more than one parameter specifier.) If &key is specified, there must remain an even number of arguments; these are considered as pairs, the first argument in each pair being interpreted as a keyword name and the second as the corresponding value.

old_change_begin
It is an error for the first object of each pair to be anything but a keyword.


Rationale: This last restriction is imposed so that a compiler may issue warnings about certain malformed calls to functions that take keyword arguments. It must be remembered that the arguments in a function call that evaluate to keywords are just like any other arguments and may be any evaluable forms. A compiler could not, without additional context, issue a warning about the call

(fill seq item x y)

because in principle the variable x might have as its value a keyword such as :start. However, a compiler would be justified in issuing a warning about the call

(fill seq item 0 10)

because the constant 0 is definitely not a keyword. Similarly, if in the first case the variable x had been declared to be of type integer, then type analysis could enable the compiler to justify a warning.


old_change_end

change_begin
X3J13 voted in March 1988 (KEYWORD-ARGUMENT-NAME-PACKAGE)   to allow a keyword in a lambda-list to be any symbol whatsoever, not just a keyword symbol in the keyword package. If, after &key, a variable appears alone or within only one set of parentheses (possibly with an initform and a svar), then the behavior is as before: a keyword symbol with the same name as the variable is used as the keyword-name when matching arguments to parameter specifiers. Only a parameter specifier of the form ((keyword var) ...) can cause the keyword-name not to be a keyword symbol, by specifying a symbol not in the keyword package as the keyword. For example:

(defun wager (&key ((secret password) nil) amount) 
  (format nil "You ~A $~D" 
          (if (eq password 'joe-sent-me) "win" "lose") 
          amount)) 

(wager :amount 100) => "You lose $100" 
(wager :amount 100 'secret 'joe-sent-me) => "You win $100"

The secret word could be made even more secret in this example by placing it in some other obscure package, so that one would have to write

(wager :amount 100 'obscure:secret 'joe-sent-me) => "You win $100"

to win anything.
change_end

In each keyword parameter specifier must be a name var for the parameter variable. If an explicit keyword is specified, then that is the keyword name for the parameter. Otherwise the name var serves to indicate the keyword name, in that a keyword with the same name (in the keyword package) is used as the keyword. Thus

(defun foo (&key radix (type 'integer)) ...)

means exactly the same as

(defun foo (&key ((:radix radix)) ((:type type) 'integer)) ...)

The keyword parameter specifiers are, like all parameter specifiers, effectively processed from left to right. For each keyword parameter specifier, if there is an argument pair whose keyword name matches that specifier's keyword name (that is, the names are eq), then the parameter variable for that specifier is bound to the second item (the value) of that argument pair. If more than one such argument pair matches, it is not an error; the leftmost argument pair is used. If no such argument pair exists, then the initform for that specifier is evaluated and the parameter variable is bound to that value (or to nil if no initform was specified). The variable svar is treated as for ordinary optional parameters: it is bound to true if there was a matching argument pair, and to false otherwise.

It is an error if an argument pair has a keyword name not matched by any parameter specifier, unless at least one of the following two conditions is met:

If either condition obtains, then it is not an error for an argument pair to match no parameter specified, and the argument pair is simply ignored (but such an argument pair is accessible through the &rest parameter if one was specified). The purpose of these mechanisms is to allow sharing of argument lists among several functions and to allow either the caller or the called function to specify that such sharing may be taking place.

After all parameter specifiers have been processed, the auxiliary variable specifiers (those following the lambda-list keyword &aux) are processed from left to right. For each one, the initform is evaluated and the variable var bound to that value (or to nil if no initform was specified). Nothing can be done with &aux variables that cannot be done with the special form let*:

(lambda (x y &aux (a (car x)) (b 2) c) ...) 
   == (lambda (x y) (let* ((a (car x)) (b 2) c) ...))

Which to use is purely a matter of style.

Whenever any initform is evaluated for any parameter specifier, that form may refer to any parameter variable to the left of the specifier in which the initform appears, including any supplied-p variables, and may rely on the fact that no other parameter variable has yet been bound (including its own parameter variable).

Once the lambda-list has been processed, the forms in the body of the lambda-expression are executed. These forms may refer to the arguments to the function by using the names of the parameters. On exit from the function, either by a normal return of the function's value(s) or by a non-local exit, the parameter bindings, whether lexical or special, are no longer in effect. (The bindings are not necessarily permanently discarded, for a lexical binding can later be reinstated if a ``closure'' over that binding was created, perhaps by using function, and saved before the exit occurred.)

Examples of &optional and &rest parameters:

((lambda (a b) (+ a (* b 3))) 4 5) => 19 
((lambda (a &optional (b 2)) (+ a (* b 3))) 4 5) => 19 
((lambda (a &optional (b 2)) (+ a (* b 3))) 4) => 10 
((lambda (&optional (a 2 b) (c 3 d) &rest x) (list a b c d x))) 
   => (2 nil 3 nil nil) 
((lambda (&optional (a 2 b) (c 3 d) &rest x) (list a b c d x)) 
 6) 
   => (6 t 3 nil nil) 
((lambda (&optional (a 2 b) (c 3 d) &rest x) (list a b c d x)) 
 6 3) 
   => (6 t 3 t nil) 
((lambda (&optional (a 2 b) (c 3 d) &rest x) (list a b c d x)) 
 6 3 8) 
   => (6 t 3 t (8)) 
((lambda (&optional (a 2 b) (c 3 d) &rest x) (list a b c d x)) 
 6 3 8 9 10 11) 
   => (6 t 3 t (8 9 10 11))

Examples of &key parameters:

((lambda (a b &key c d) (list a b c d)) 1 2) 
   => (1 2 nil nil) 
((lambda (a b &key c d) (list a b c d)) 1 2 :c 6) 
   => (1 2 6 nil) 
((lambda (a b &key c d) (list a b c d)) 1 2 :d 8) 
   => (1 2 nil 8) 
((lambda (a b &key c d) (list a b c d)) 1 2 :c 6 :d 8) 
   => (1 2 6 8) 
((lambda (a b &key c d) (list a b c d)) 1 2 :d 8 :c 6) 
   => (1 2 6 8) 
((lambda (a b &key c d) (list a b c d)) :a 1 :d 8 :c 6) 
   => (:a 1 6 8) 
((lambda (a b &key c d) (list a b c d)) :a :b :c :d) 
   => (:a :b :d nil)

Examples of mixtures:

((lambda (a &optional (b 3) &rest x &key c (d a)) 
   (list a b c d x)) 
 1)   => (1 3 nil 1 ())

((lambda (a &optional (b 3) &rest x &key c (d a)) 
   (list a b c d x)) 
 1 2)   => (1 2 nil 1 ()) 

((lambda (a &optional (b 3) &rest x &key c (d a)) 
   (list a b c d x)) 
 :c 7)   => (:c 7 nil :c ()) 

((lambda (a &optional (b 3) &rest x &key c (d a)) 
   (list a b c d x)) 
 1 6 :c 7)   => (1 6 7 1 (:c 7)) 

((lambda (a &optional (b 3) &rest x &key c (d a)) 
   (list a b c d x)) 
 1 6 :d 8)   => (1 6 nil 8 (:d 8)) 

((lambda (a &optional (b 3) &rest x &key c (d a)) 
   (list a b c d x)) 
 1 6 :d 8 :c 9 :d 10)   => (1 6 9 8 (:d 8 :c 9 :d 10))

All lambda-list keywords are permitted, but not terribly useful, in lambda-expressions appearing explicitly as the first element of a function-call form. They are extremely useful, however, in functions given global names by defun.

All symbols whose names begin with & are conventionally reserved for use as lambda-list keywords and should not be used as variable names. Implementations of Common Lisp are free to provide additional lambda-list keywords.


[Constant]
lambda-list-keywords

The value of lambda-list-keywords is a list of all the lambda-list keywords used in the implementation, including the additional ones used only by defmacro. This list must contain at least the symbols &optional, &rest, &key, &allow-other-keys, &aux, &body, &whole, and &environment.

As an example of the use of &allow-other-keys and :allow-other-keys, consider a function that takes two keyword arguments of its own and also accepts additional keyword arguments to be passed to make-array:

(defun array-of-strings (str dims &rest keyword-pairs 
                         &key (start 0) end &allow-other-keys) 
  (apply #'make-array dims 
         :initial-element (subseq str start end) 
         :allow-other-keys t 
         keyword-pairs))

This function takes a string and dimensioning information and returns an array of the specified dimensions, each of whose elements is the specified string. However, :start and :end keyword arguments may be used in the usual manner (see chapter 14) to specify that a substring of the given string should be used. In addition, the presence of &allow-other-keys in the lambda-list indicates that the caller may specify additional keyword arguments; the &rest argument provides access to them. These additional keyword arguments are fed to make-array. Now, make-array normally does not allow the keywords :start and :end to be used, and it would be an error to specify such keyword arguments to make-array. However, the presence in the call to make-array of the keyword argument :allow-other-keys with a non-nil value causes any extraneous keyword arguments, including :start and :end, to be acceptable and ignored.


[Constant]
lambda-parameters-limit

The value of lambda-parameters-limit is a positive integer that is the upper exclusive bound on the number of distinct parameter names that may appear in a single lambda-list. This bound depends on the implementation but will not be smaller than 50. Implementors are encouraged to make this limit as large as practicable without sacrificing performance. See call-arguments-limit.



next up previous contents index
Next: Top-Level Forms Up: Functions Previous: Named Functions


AI.Repository@cs.cmu.edu