Anonymous Functions
Once you start writing, or even simply using, functions that accept other functions as arguments, you’re bound to discover that sometimes it’s annoying to have to define and name a whole separate function that’s used in only one place, especially when you never call it by name.
When it seems like overkill to define a new function with **DEFUN**
, you can create an “anonymous” function using a **LAMBDA**
expression. As discussed in Chapter 3, a **LAMBDA**
expression looks like this:
(lambda (parameters) body)
One way to think of **LAMBDA**
expressions is as a special kind of function name where the name itself directly describes what the function does. This explains why you can use a **LAMBDA**
expression in the place of a function name with #'
.
(funcall #'(lambda (x y) (+ x y)) 2 3) ==> 5
You can even use a **LAMBDA**
expression as the “name” of a function in a function call expression. If you wanted, you could write the previous **FUNCALL**
expression more concisely.
((lambda (x y) (+ x y)) 2 3) ==> 5
But this is almost never done; it’s merely worth noting that it’s legal in order to emphasize that **LAMBDA**
expressions can be used anywhere a normal function name can be.13
Anonymous functions can be useful when you need to pass a function as an argument to another function and the function you need to pass is simple enough to express inline. For instance, suppose you wanted to plot the function 2x. You could define the following function:
(defun double (x) (* 2 x))
which you could then pass to plot
.
CL-USER> (plot #'double 0 10 1)
**
****
******
********
**********
************
**************
****************
******************
********************
NIL
But it’s easier, and arguably clearer, to write this:
CL-USER> (plot #'(lambda (x) (* 2 x)) 0 10 1)
**
****
******
********
**********
************
**************
****************
******************
********************
NIL
The other important use of **LAMBDA**
expressions is in making closures, functions that capture part of the environment where they’re created. You used closures a bit in Chapter 3, but the details of how closures work and what they’re used for is really more about how variables work than functions, so I’ll save that discussion for the next chapter.
1Despite the importance of functions in Common Lisp, it isn’t really accurate to describe it as a functional language. It’s true some of Common Lisp’s features, such as its list manipulation functions, are designed to be used in a body-form* style and that Lisp has a prominent place in the history of functional programming—McCarthy introduced many ideas that are now considered important in functional programming—but Common Lisp was intentionally designed to support many different styles of programming. In the Lisp family, Scheme is the nearest thing to a “pure” functional language, and even it has several features that disqualify it from absolute purity compared to languages such as Haskell and ML.
2Well, almost any symbol. It’s undefined what happens if you use any of the names defined in the language standard as a name for one of your own functions. However, as you’ll see in Chapter 21, the Lisp package system allows you to create names in different namespaces, so this isn’t really an issue.
3Parameter lists are sometimes also called lambda lists because of the historical relationship between Lisp’s notion of functions and the lambda calculus.
4For example, the following:
(documentation 'foo 'function)
returns the documentation string for the function foo
. Note, however, that documentation strings are intended for human consumption, not programmatic access. A Lisp implementation isn’t required to store them and is allowed to discard them at any time, so portable programs shouldn’t depend on their presence. In some implementations an implementation-defined variable needs to be set before it will store documentation strings.
5In languages that don’t support optional parameters directly, programmers typically find ways to simulate them. One technique is to use distinguished “no-value” values that the caller can pass to indicate they want the default value of a given parameter. In C, for example, it’s common to use NULL
as such a distinguished value. However, such a protocol between the function and its callers is ad hoc—in some functions or for some arguments NULL
may be the distinguished value while in other functions or for other arguments the magic value may be -1 or some #defined
constant.
6The constant **CALL-ARGUMENTS-LIMIT**
tells you the implementation-specific value.
7Four standard functions take both **&optional**
and **&key**
arguments—**READ-FROM-STRING**
, **PARSE-NAMESTRING**
, **WRITE-LINE**
, and **WRITE-STRING**
. They were left that way during standardization for backward compatibility with earlier Lisp dialects. **READ-FROM-STRING**
tends to be the one that catches new Lisp programmers most frequently—a call such as (read-from-string s :start 10)
seems to ignore the :start
keyword argument, reading from index 0 instead of 10. That’s because **READ-FROM-STRING**
also has two **&optional**
parameters that swallowed up the arguments :start
and 10.
8Another macro, **RETURN**
, doesn’t require a name. However, you can’t use it instead of **RETURN-FROM**
to avoid having to specify the function name; it’s syntactic sugar for returning from a block named **NIL**
. I’ll cover it, along with the details of **BLOCK**
and **RETURN-FROM**
, in Chapter 20.
9Lisp, of course, isn’t the only language to treat functions as data. C uses function pointers, Perl uses subroutine references, Python uses a scheme similar to Lisp, and C# introduces delegates, essentially typed function pointers, as an improvement over Java’s rather clunky reflection and anonymous class mechanisms.
10The exact printed representation of a function object will differ from implementation to implementation.
11The best way to think of **FUNCTION**
is as a special kind of quotation. **QUOTE**
ing a symbol prevents it from being evaluated at all, resulting in the symbol itself rather than the value of the variable named by that symbol. **FUNCTION**
also circumvents the normal evaluation rule but, instead of preventing the symbol from being evaluated at all, causes it to be evaluated as the name of a function, just the way it would if it were used as the function name in a function call expression.
12There’s actually a third, the special operator **MULTIPLE-VALUE-CALL**
, but I’ll save that for when I discuss expressions that return multiple values in Chapter 20.
13In Common Lisp it’s also possible to use a **LAMBDA**
expression as an argument to **FUNCALL**
(or some other function that takes a function argument such as **SORT**
or **MAPCAR**
) with no #'
before it, like this:
(funcall (lambda (x y) (+ x y)) 2 3)
This is legal and is equivalent to the version with the #'
but for a tricky reason. Historically **LAMBDA**
expressions by themselves weren’t expressions that could be evaluated. That is **LAMBDA**
wasn’t the name of a function, macro, or special operator. Rather, a list starting with the symbol **LAMBDA**
was a special syntactic construct that Lisp recognized as a kind of function name.
But if that were still true, then (funcall (lambda (...) ...))
would be illegal because **FUNCALL**
is a function and the normal evaluation rule for a function call would require that the **LAMBDA**
expression be evaluated. However, late in the ANSI standardization process, in order to make it possible to implement ISLISP, another Lisp dialect being standardized at the same time, strictly as a user-level compatibility layer on top of Common Lisp, a **LAMBDA**
macro was defined that expands into a call to **FUNCTION**
wrapped around the **LAMBDA**
expression. In other words, the following **LAMBDA**
expression:
(lambda () 42)
exands into the following when it occurs in a context where it evaluated:
(function (lambda () 42)) ; or #'(lambda () 42)
This makes its use in a value position, such as an argument to **FUNCALL**
, legal. In other words, it’s pure syntactic sugar. Most folks either always use #'
before **LAMBDA**
expressions in value positions or never do. In this book, I always use #'
.