parameters, you should probably just change it to use all &key
parameters—they're more flexible, and you can always add new keyword parameters without disturbing existing callers of the function. You can also remove keyword parameters, as long as no one is using them.[60] In general, using keyword parameters helps make code much easier to maintain and evolve—if you need to add some new behavior to a function that requires new parameters, you can add keyword parameters without having to touch, or even recompile, any existing code that calls the function.
You can safely combine &rest
and &key
parameters, but the behavior may be a bit surprising initially. Normally the presence of either &rest
or &key
in a parameter list causes all the values remaining after the required and &optional
parameters have been filled in to be processed in a particular way—either gathered into a list for a &rest
parameter or assigned to the appropriate &key
parameters based on the keywords. If both &rest
and &key
appear in a parameter list, then both things happen—all the remaining values, which include the keywords themselves, are gathered into a list that's bound to the &rest
parameter, and the appropriate values are also bound to the &key
parameters. So, given this function:
(defun foo (&rest rest &key a b c) (list rest a b c))
you get this result:
(foo :a 1 :b 2 :c 3) ==> ((:A 1 :B 2 :C 3) 1 2 3)
All the functions you've written so far have used the default behavior of returning the value of the last expression evaluated as their own return value. This is the most common way to return a value from a function.
However, sometimes it's convenient to be able to return from the middle of a function such as when you want to break out of nested control constructs. In such cases you can use the RETURN- FROM
special operator to immediately return any value from the function.
You'll see in Chapter 20 that RETURN-FROM
is actually not tied to functions at all; it's used to return from a block of code defined with the BLOCK
special operator. However, DEFUN
automatically wraps the whole function body in a block with the same name as the function. So, evaluating a RETURN-FROM
with the name of the function and the value you want to return will cause the function to immediately exit with that value. RETURN-FROM
is a special operator whose first 'argument' is the name of the block from which to return. This name isn't evaluated and thus isn't quoted.
The following function uses nested loops to find the first pair of numbers, each less than 10, whose product is greater than the argument, and it uses RETURN-FROM
to return the pair as soon as it finds it:
(defun foo (n)
(dotimes (i 10)
(dotimes (j 10)
(when (> (* i j) n)
(return-from foo (list i j))))))
Admittedly, having to specify the name of the function you're returning from is a bit of a pain—for one thing, if you change the function's name, you'll need to change the name used in the RETURN- FROM
as well.[61] But it's also the case that explicit RETURN-FROM
s are used much less frequently in Lisp than return
statements in C-derived languages, because
While the main way you use functions is to call them by name, a number of situations exist where it's useful to be able treat functions as data. For instance, if you can pass one function as an argument to another, you can write a general-purpose sorting function while allowing the caller to provide a function that's responsible for comparing any two elements. Then the same underlying algorithm can be used with many different comparison functions. Similarly, callbacks and hooks depend on being able to store references to code in order to run it later. Since functions are already the standard way to abstract bits of code, it makes sense to allow functions to be treated as data.[62]
In Lisp, functions are just another kind of object. When you define a function with DEFUN
, you're really doing two things: creating a new function object and giving it a name. It's also possible, as you saw in Chapter 3, to use LAMBDA
expressions to create a function without giving it a name. The actual representation of a function object, whether named or anonymous, is opaque—in a native-compiling Lisp, it probably consists mostly of machine code. The only things you need to know are how to get hold of it and how to invoke it once you've got it.
The special operator FUNCTION
provides the mechanism for getting at a function object. It takes a single argument and returns the function with that name. The name isn't quoted. Thus, if you've defined a function foo
, like so:
CL-USER> (defun foo (x) (* 2 x))
FOO
you can get the function object like this:[63]
CL-USER> (function foo)
#<Interpreted Function FOO>
In fact, you've already used FUNCTION
, but it was in disguise. The syntax #'
, which you used in Chapter 3, is syntactic sugar for FUNCTION
, just the way '
is syntactic sugar for QUOTE
.[64] Thus, you can also get the function object for foo
like this:
CL-USER> #'foo
#<Interpreted Function FOO>
Once you've got the function object, there's really only one thing you can do with it—invoke it. Common Lisp provides two functions for invoking a function through a function object: FUNCALL
and APPLY
.[65] They differ only in how they obtain the arguments to pass to the function.
FUNCALL
is the one to use when you know the number of arguments you're going to pass to the function at the time you write the code. The first argument to FUNCALL
is the function object to be invoked, and the rest of the arguments are passed onto that function. Thus, the following two expressions are equivalent:
(foo 1 2 3) === (funcall #'foo 1 2 3)
However, there's little point in using FUNCALL
to call a function whose