After the rules of syntax and semantics, the three most basiccomponents of all Lisp programs are functions, variables and macros.You used all three while building the database in Chapter 3, but Iglossed over a lot of the details of how they work and how to bestuse them. I'll devote the next few chapters to these three topics,starting with functions, which--like their counterparts in otherlanguages--provide the basic mechanism for abstracting, well,functionality.
The bulk of Lisp itself consists of functions. More than threequarters of the names defined in the language standard namefunctions. All the built-in data types are defined purely in terms ofwhat functions operate on them. Even Lisp's powerful object system isbuilt upon a conceptual extension to functions, generic functions,which I'll cover in Chapter 16.
And, despite the importance of macros to The Lisp Way, in the end allreal functionality is provided by functions. Macros run at compiletime, so the code they generate--the code that will actually make upthe program after all the macros are expanded--will consist entirelyof calls to functions and special operators. Not to mention, macrosthemselves are also functions, albeit functions that are used togenerate code rather than to perform the actions of theprogram.1
Normally functions are defined using theDEFUN
macro. The basicskeleton of aDEFUN
looks like this:
(defunname (parameter*) "Optional documentation string."body-form*)
Any symbol can be used as a function name.2 Usually function names contain onlyalphabetic characters and hyphens, but other characters are allowedand are used in certain naming conventions. For instance, functionsthat convert one kind of value to another sometimes use->
inthe name. For example, a function to convert strings to widgets mightbe calledstring->widget
. The most important naming conventionis the one mentioned in Chapter 2, which is that you constructcompound names with hyphens rather than underscores or inner caps.Thus,frob-widget
is better Lisp style than eitherfrob_widget
orfrobWidget
.
A function's parameter list defines the variables that will be usedto hold the arguments passed to the function when it'scalled.3 If the function takes noarguments, the list is empty, written as()
. Different flavorsof parameters handle required, optional, multiple, and keywordarguments. I'll discuss the details in the next section.
If a string literal follows the parameter list, it's a documentationstring that should describe the purpose of the function. When thefunction is defined, the documentation string will be associated withthe name of the function and can later be obtained using theDOCUMENTATION
function.4
Finally, the body of aDEFUN
consists of any number of Lispexpressions. They will be evaluated in order when the function iscalled and the value of the last expression is returned as the valueof the function. Or theRETURN-FROM
special operator can be usedto return immediately from anywhere in a function, as I'll discuss ina moment.
In Chapter 2 we wrote ahello-world
function, which lookedlike this:
(defun hello-world () (format t "hello, world"))
You can now analyze the parts of this function. Its name ishello-world
, its parameter list is empty so it takes noarguments, it has no documentation string, and its body consists ofone expression.
(format t "hello, world")
The following is a slightly more complex function:
(defun verbose-sum (x y) "Sum any two numbers after printing a message." (format t "Summing ~d and ~d.~%" x y) (+ x y))
This function is namedverbose-sum
, takes two arguments thatwill be bound to the parametersx
andy
, has adocumentation string, and has a body consisting of two expressions.The value returned by the call to+
becomes the return value ofverbose-sum
.
There's not a lot more to say about function names or documentationstrings, and it will take a good portion of the rest of this book todescribe all the things you can do in the body of a function, whichleaves us with the parameter list.
The basic purpose of a parameter list is, of course, to declare thevariables that will receive the arguments passed to the function.When a parameter list is a simple list of variable names--as inverbose-sum
--the parameters are calledrequiredparameters. When a function is called, it must be supplied with oneargument for every required parameter. Each parameter is bound to thecorresponding argument. If a function is called with too few or toomany arguments, Lisp will signal an error.
However, Common Lisp's parameter lists also give you more flexibleways of mapping the arguments in a function call to the function'sparameters. In addition to required parameters, a function can haveoptional parameters. Or a function can have a single parameter that'sbound to a list containing any extra arguments. And, finally,arguments can be mapped to parameters using keywords rather thanposition. Thus, Common Lisp's parameter lists provide a convenientsolution to several common coding problems.
While many functions, likeverbose-sum
, need only requiredparameters, not all functions are quite so simple. Sometimes afunction will have a parameter that only certain callers will careabout, perhaps because there's a reasonable default value. An exampleis a function that creates a data structure that can grow as needed.Since the data structure can grow, it doesn't matter--from acorrectness point of view--what the initial size is. But callers whohave a good idea how many items they're going to put into the datastructure may be able to improve performance by specifying a specificinitial size. Most callers, though, would probably rather let thecode that implements the data structure pick a good general-purposevalue. In Common Lisp you can accommodate both kinds of callers byusing an optional parameter; callers who don't care will get areasonable default, and other callers can provide a specificvalue.5
To define a function with optional parameters, after the names of anyrequired parameters, place the symbol&optional
followed by thenames of the optional parameters. A simple example looks like this:
(defun foo (a b &optional c d) (list a b c d))
When the function is called, arguments are first bound to therequired parameters. After all the required parameters have beengiven values, if there are any arguments left, their values areassigned to the optional parameters. If the arguments run out beforethe optional parameters do, the remaining optional parameters arebound to the valueNIL
. Thus, the function defined previouslygives the following results:
(foo 1 2) ==> (1 2 NIL NIL)(foo 1 2 3) ==> (1 2 3 NIL)(foo 1 2 3 4) ==> (1 2 3 4)
Lisp will still check that an appropriate number of arguments arepassed to the function--in this case between two and four,inclusive--and will signal an error if the function is called withtoo few or too many.
Of course, you'll often want a different default value thanNIL
.You can specify the default value by replacing the parameter namewith a list containing a name and an expression. The expression willbe evaluated only if the caller doesn't pass enough arguments toprovide a value for the optional parameter. The common case is simplyto provide a value as the expression.
(defun foo (a &optional (b 10)) (list a b))
This function requires one argument that will be bound to theparametera
. The second parameter,b
, will take eitherthe value of the second argument, if there is one, or 10.
(foo 1 2) ==> (1 2)(foo 1) ==> (1 10)
Sometimes, however, you may need more flexibility in choosing thedefault value. You may want to compute a default value based on otherparameters. And you can--the default-value expression can refer toparameters that occur earlier in the parameter list. If you werewriting a function that returned some sort of representation of arectangle and you wanted to make it especially convenient to makesquares, you might use an argument list like this:
(defun make-rectangle (width &optional (height width)) ...)
which would cause theheight
parameter to take the same valueas thewidth
parameter unless explicitly specified.
Occasionally, it's useful to know whether the value of an optionalargument was supplied by the caller or is the default value. Ratherthan writing code to check whether the value of the parameter is thedefault (which doesn't work anyway, if the caller happens toexplicitly pass the default value), you can add another variable nameto the parameter specifier after the default-value expression. Thisvariable will be bound to true if the caller actually supplied anargument for this parameter andNIL
otherwise. By convention,these variables are usually named the same as the actual parameterwith a "-supplied-p" on the end. For example:
(defun foo (a b &optional (c 3 c-supplied-p)) (list a b c c-supplied-p))
This gives results like this:
(foo 1 2) ==> (1 2 3 NIL)(foo 1 2 3) ==> (1 2 3 T)(foo 1 2 4) ==> (1 2 4 T)
Optional parameters are just the thing when you have discreteparameters for which the caller may or may not want to providevalues. But some functions need to take a variable number ofarguments. Several of the built-in functions you've seen already workthis way.FORMAT
has two required arguments, the stream and thecontrol string. But after that it needs a variable number ofarguments depending on how many values need to be interpolated intothe control string. The+
function also takes a variable numberof arguments--there's no particular reason to limit it to summingjust two numbers; it will sum any number of values. (It even workswith zero arguments, returning 0, the identity under addition.) Thefollowing are all legal calls of those two functions:
(format t "hello, world")(format t "hello, ~a" name)(format t "x: ~d y: ~d" x y)(+)(+ 1)(+ 1 2)(+ 1 2 3)
Obviously, you could write functions taking a variable number ofarguments by simply giving them a lot of optional parameters. Butthat would be incredibly painful--just writing the parameter listwould be bad enough, and that doesn't get into dealing with all theparameters in the body of the function. To do it properly, you'd haveto have as many optional parameters as the number of arguments thatcan legally be passed in a function call. This number isimplementation dependent but guaranteed to be at least 50. And incurrent implementations it ranges from 4,096 to 536,870,911.6 Blech. That kind of mind-bendingtedium is definitelynot The Lisp Way.
Instead, Lisp lets you include a catchall parameter after the symbol&rest
. If a function includes a&rest
parameter, anyarguments remaining after values have been doled out to all therequired and optional parameters are gathered up into a list thatbecomes the value of the&rest
parameter. Thus, the parameterlists forFORMAT
and+
probably look something like this:
(defun format (stream string &rest values) ...)(defun + (&rest numbers) ...)
Optional and rest parameters give you quite a bit of flexibility, butneither is going to help you out much in the following situation:Suppose you have a function that takes four optional parameters. Nowsuppose that most of the places the function is called, the callerwants to provide a value for only one of the four parameters and,further, that the callers are evenly divided as to which parameterthey will use.
The callers who want to provide a value for the first parameter arefine--they just pass the one optional argument and leave off therest. But all the other callers have to pass some value for betweenone and three arguments they don't care about. Isn't that exactly theproblem optional parameters were designed to solve?
Of course it is. The problem is that optional parameters are stillpositional--if the caller wants to pass an explicit value for thefourth optional parameter, it turns the first three optionalparameters into required parameters for that caller. Luckily, anotherparameter flavor, keyword parameters, allow the caller to specifywhich values go with which parameters.
To give a function keyword parameters, after any required,&optional
, and&rest
parameters you include the symbol&key
and then any number of keyword parameter specifiers, whichwork like optional parameter specifiers. Here's a function that hasonly keyword parameters:
(defun foo (&key a b c) (list a b c))
When this function is called, each keyword parameters is bound to thevalue immediately following a keyword of the same name. Recall fromChapter 4 that keywords are names that start with a colon and thatthey're automatically defined as self-evaluating constants.
If a given keyword doesn't appear in the argument list, then thecorresponding parameter is assigned its default value, just like anoptional parameter. Because the keyword arguments are labeled, theycan be passed in any order as long as they follow any requiredarguments. For instance,foo
can be invoked as follows:
(foo) ==> (NIL NIL NIL)(foo :a 1) ==> (1 NIL NIL)(foo :b 1) ==> (NIL 1 NIL)(foo :c 1) ==> (NIL NIL 1)(foo :a 1 :c 3) ==> (1 NIL 3)(foo :a 1 :b 2 :c 3) ==> (1 2 3)(foo :a 1 :c 3 :b 2) ==> (1 2 3)
As with optional parameters, keyword parameters can provide a defaultvalue form and the name of a supplied-p variable. In both keyword andoptional parameters, the default value form can refer to parametersthat appear earlier in the parameter list.
(defun foo (&key (a 0) (b 0 b-supplied-p) (c (+ a b))) (list a b c b-supplied-p))(foo :a 1) ==> (1 0 1 NIL)(foo :b 1) ==> (0 1 1 T)(foo :b 1 :c 4) ==> (0 1 4 T)(foo :a 2 :b 1 :c 4) ==> (2 1 4 T)
Also, if for some reason you want the keyword the caller uses tospecify the parameter to be different from the name of the actualparameter, you can replace the parameter name with another listcontaining the keyword to use when calling the function and the nameto be used for the parameter. The following definition offoo
:
(defun foo (&key ((:apple a)) ((:box b) 0) ((:charlie c) 0 c-supplied-p)) (list a b c c-supplied-p))
lets the caller call it like this:
(foo :apple 10 :box 20 :charlie 30) ==> (10 20 30 T)
This style is mostly useful if you want to completely decouple thepublic API of the function from the internal details, usually becauseyou want to use short variable names internally but descriptivekeywords in the API. It's not, however, very frequently used.
It's possible, but rare, to use all four flavors of parameters in asingle function. Whenever more than one flavor of parameter is used,they must be declared in the order I've discussed them: first thenames of the required parameters, then the optional parameters, thenthe rest parameter, and finally the keyword parameters. Typically,however, in functions that use multiple flavors of parameters, you'llcombine required parameters with one other flavor or possibly combine&optional
and&rest
parameters. The other two combinations,either&optional
or&rest
parameters combined with&key
parameters, can lead to somewhat surprising behavior.
Combining&optional
and&key
parameters yields surprisingenough results that you should probably avoid it altogether. Theproblem is that if a caller doesn't supply values for all theoptional parameters, then those parameters will eat up the keywordsand values intended for the keyword parameters. For instance, thisfunction unwisely mixes&optional
and&key
parameters:
(defun foo (x &optional y &key z) (list x y z))
If called like this, it works fine:
(foo 1 2 :z 3) ==> (1 2 3)
And this is also fine:
(foo 1) ==> (1 nil nil)
But this will signal an error:
(foo 1 :z 3) ==>ERROR
This is because the keyword:z
is taken as a value to fill theoptionaly
parameter, leaving only the argument 3 to beprocessed. At that point, Lisp will be expecting either akeyword/value pair or nothing and will complain. Perhaps even worse,if the function had had two&optional
parameters, this last callwould have resulted in the values:z
and 3 being bound to thetwo&optional
parameters and the&key
parameterz
getting the default valueNIL
with no indication that anythingwas amiss.
In general, if you find yourself writing a function that uses both&optional
and&key
parameters, you should probably justchange it to use all&key
parameters--they're more flexible, andyou can always add new keyword parameters without disturbing existingcallers of the function. You can also remove keyword parameters, aslong as no one is using them.7 Ingeneral, using keyword parameters helps make code much easier tomaintain and evolve--if you need to add some new behavior to afunction that requires new parameters, you can add keyword parameterswithout having to touch, or even recompile, any existing code thatcalls the function.
You can safely combine&rest
and&key
parameters, but thebehavior may be a bit surprising initially. Normally the presence ofeither&rest
or&key
in a parameter list causes all thevalues remaining after the required and&optional
parametershave been filled in to be processed in a particular way--eithergathered into a list for a&rest
parameter or assigned to theappropriate&key
parameters based on the keywords. If both&rest
and&key
appear in a parameter list, then both thingshappen--all the remaining values, which include the keywordsthemselves, 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 defaultbehavior of returning the value of the last expression evaluated astheir own return value. This is the most common way to return a valuefrom a function.
However, sometimes it's convenient to be able to return from themiddle of a function such as when you want to break out of nestedcontrol constructs. In such cases you can use theRETURN-FROM
special operator to immediately return any value from the function.
You'll see in Chapter 20 thatRETURN-FROM
is actually not tiedto functions at all; it's used to return from a block of code definedwith theBLOCK
special operator. However,DEFUN
automatically wraps the whole function body in a block with the samename as the function. So, evaluating aRETURN-FROM
with the nameof the function and the value you want to return will cause thefunction to immediately exit with that value.RETURN-FROM
is aspecial operator whose first "argument" is the name of the block fromwhich to return. This name isn't evaluated and thus isn't quoted.
The following function uses nested loops to find the first pair ofnumbers, each less than 10, whose product is greater than theargument, and it usesRETURN-FROM
to return the pair as soon asit 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'rereturning from is a bit of a pain--for one thing, if you change thefunction's name, you'll need to change the name used in theRETURN-FROM
as well.8 Butit's also the case that explicitRETURN-FROM
s are used much lessfrequently in Lisp thanreturn
statements in C-derivedlanguages, becauseall Lisp expressions, including controlconstructs such as loops and conditionals, evaluate to a value. Soit's not much of a problem in practice.
While the main way you use functions is to call them by name, anumber of situations exist where it's useful to be able treatfunctions as data. For instance, if you can pass one function as anargument to another, you can write a general-purpose sorting functionwhile allowing the caller to provide a function that's responsiblefor comparing any two elements. Then the same underlying algorithmcan be used with many different comparison functions. Similarly,callbacks and hooks depend on being able to store references to codein order to run it later. Since functions are already the standardway to abstract bits of code, it makes sense to allow functions to betreated as data.9
In Lisp, functions are just another kind of object. When you define afunction withDEFUN
, you're really doing two things: creating anew function object and giving it a name. It's also possible, as yousaw in Chapter 3, to useLAMBDA
expressions to create a functionwithout giving it a name. The actual representation of a functionobject, whether named or anonymous, is opaque--in a native-compilingLisp, it probably consists mostly of machine code. The only thingsyou need to know are how to get hold of it and how to invoke it onceyou've got it.
The special operatorFUNCTION
provides the mechanism for gettingat a function object. It takes a single argument and returns thefunction with that name. The name isn't quoted. Thus, if you'vedefined a functionfoo
, like so:
CL-USER> (defun foo (x) (* 2 x))FOO
you can get the function object like this:10
CL-USER> (function foo)#<Interpreted Function FOO>
In fact, you've already usedFUNCTION
, but it was in disguise.The syntax#'
, which you used in Chapter 3, is syntactic sugarforFUNCTION
, just the way'
is syntactic sugar forQUOTE
.11 Thus, you can also getthe function object forfoo
like this:
CL-USER> #'foo#<Interpreted Function FOO>
Once you've got the function object, there's really only one thingyou can do with it--invoke it. Common Lisp provides two functionsfor invoking a function through a function object:FUNCALL
andAPPLY
.12 They differonly in how they obtain the arguments to pass to the function.
FUNCALL
is the one to use when you know the number of argumentsyou're going to pass to the function at the time you write the code.The first argument toFUNCALL
is the function object to beinvoked, 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 usingFUNCALL
to call afunction whose name you know when you write the code. In fact, theprevious two expressions will quite likely compile to exactly thesame machine instructions.
The following function demonstrates a more apt use ofFUNCALL
.It accepts a function object as an argument and plots a simpleASCII-art histogram of the values returned by the argument functionwhen it's invoked on the values frommin
tomax
,stepping bystep
.
(defun plot (fn min max step) (loop for i from min to max by step do (loop repeat (funcall fn i) do (format t "*")) (format t "~%")))
TheFUNCALL
expression computes the value of the function foreach value ofi
. The innerLOOP
uses that computed valueto determine how many times to print an asterisk to standard output.
Note that you don't useFUNCTION
or#'
to get thefunction value offn
; youwant it to be interpreted as avariable because it's the variable's value that will be the functionobject. You can callplot
with any function that takes asingle numeric argument, such as the built-in functionEXP
thatreturns the value ofe raised to the power of its argument.
CL-USER> (plot #'exp 0 4 1/2)**************************************************************************************************************************************NIL
FUNCALL
, however, doesn't do you any good when the argument listis known only at runtime. For instance, to stick with theplot
function for another moment, suppose you've obtained a listcontaining a function object, a minimum and maximum value, and a stepvalue. In other words, the list contains the values you want to passas arguments toplot
. Suppose this list is in the variableplot-data
. You could invokeplot
on the values in thatlist like this:
(plot (first plot-data) (second plot-data) (third plot-data) (fourth plot-data))
This works fine, but it's pretty annoying to have to explicitlyunpack the arguments just so you can pass them toplot
.
That's whereAPPLY
comes in. LikeFUNCALL
, the firstargument toAPPLY
is a function object. But after the functionobject, instead of individual arguments, it expects a list. It thenapplies the function to the values in the list. This allows you towrite the following instead:
(apply #'plot plot-data)
As a further convenience,APPLY
can also accept "loose"arguments as long as the last argument is a list. Thus, ifplot-data
contained just the min, max, and step values, youcould still useAPPLY
like this to plot theEXP
functionover that range:
(apply #'plot #'exp plot-data)
APPLY
doesn't care about whether the function being appliedtakes&optional
,&rest
, or&key
arguments--theargument list produced by combining any loose arguments with thefinal list must be a legal argument list for the function with enougharguments for all the required parameters and only appropriatekeyword parameters.
Once you start writing, or even simply using, functions that acceptother functions as arguments, you're bound to discover that sometimesit's annoying to have to define and name a whole separate functionthat's used in only one place, especially when you never call it byname.
When it seems like overkill to define a new function withDEFUN
,you can create an "anonymous" function using aLAMBDA
expression. As discussed in Chapter 3, aLAMBDA
expression lookslike this:
(lambda (parameters)body)
One way to think ofLAMBDA
expressions is as a special kind offunction name where the name itself directly describes what thefunction does. This explains why you can use aLAMBDA
expressionin the place of a function name with#'
.
(funcall #'(lambda (x y) (+ x y)) 2 3) ==> 5
You can even use aLAMBDA
expression as the "name" of a functionin a function call expression. If you wanted, you could write thepreviousFUNCALL
expression more concisely.
((lambda (x y) (+ x y)) 2 3) ==> 5
But this is almost never done; it's merely worth noting that it'slegal in order to emphasize thatLAMBDA
expressions can be usedanywhere a normal function name can be.13
Anonymous functions can be useful when you need to pass a function asan argument to another function and the function you need to pass issimple enough to express inline. For instance, suppose you wanted toplot the function2x. Youcould define the followingfunction:
(defun double (x) (* 2 x))
which you could then pass toplot
.
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 ofLAMBDA
expressions is in makingclosures, functions that capture part of the environment wherethey're created. You used closures a bit in Chapter 3, but thedetails of how closures work and what they're used for is really moreabout how variables work than functions, so I'll save that discussionfor the next chapter.
1Despite the importance of functions in Common Lisp, itisn't really accurate to describe it as afunctional language.It's true some of Common Lisp's features, such as its listmanipulation functions, are designed to be used in a body-form* styleand that Lisp has a prominent place in the history of functionalprogramming--McCarthy introduced many ideas that are now consideredimportant in functional programming--but Common Lisp wasintentionally designed to support many different styles ofprogramming. In the Lisp family, Scheme is the nearest thing to a"pure" functional language, and even it has several features thatdisqualify it from absolute purity compared to languages such asHaskell and ML.
2Well, almost anysymbol. It's undefined what happens if you use any of the namesdefined in the language standard as a name for one of your ownfunctions. However, as you'll see in Chapter 21, the Lisp packagesystem allows you to create names in different namespaces, so thisisn't really an issue.
3Parameter lists are sometimes also calledlambdalists because of the historical relationship between Lisp's notionof functions and the lambda calculus.
4For example, the following:
(documentation 'foo 'function)
returns the documentation string for the functionfoo
. Note,however, that documentation strings are intended for humanconsumption, not programmatic access. A Lisp implementation isn'trequired to store them and is allowed to discard them at any time,so portable programs shouldn't depend on their presence. In someimplementations an implementation-defined variable needs to be setbefore it will store documentation strings.
5In languages that don't support optional parametersdirectly, programmers typically find ways to simulate them. Onetechnique is to use distinguished "no-value" values that the callercan pass to indicate they want the default value of a givenparameter. In C, for example, it's common to useNULL
as sucha distinguished value. However, such a protocol between the functionand its callers is ad hoc--in some functions or for some argumentsNULL
may be the distinguished value while in other functionsor for other arguments the magic value may be -1 or some#defined
constant.
6TheconstantCALL-ARGUMENTS-LIMIT
tells you theimplementation-specific value.
7Four standard functions takeboth &optional
and&key
arguments--READ-FROM-STRING
,PARSE-NAMESTRING
,WRITE-LINE
, andWRITE-STRING
. Theywere left that way during standardization for backward compatibilitywith earlier Lisp dialects.READ-FROM-STRING
tends to be the onethat 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 becauseREAD-FROM-STRING
also has two&optional
parameters that swallowed up the arguments:start
and 10.
8Another macro,RETURN
, doesn'trequire a name. However, you can't use it instead ofRETURN-FROM
to avoid having to specify the function name; it's syntactic sugarfor returning from a block namedNIL
. I'll cover it, along withthe details ofBLOCK
andRETURN-FROM
, in Chapter 20.
9Lisp, of course, isn't the only language totreat functions as data. C uses function pointers, Perl usessubroutine references, Python uses a scheme similar to Lisp, and C#introduces delegates, essentially typed function pointers, as animprovement over Java's rather clunky reflection and anonymous classmechanisms.
10The exact printedrepresentation of a function object will differ from implementationto implementation.
11The best way to think ofFUNCTION
is as aspecial kind of quotation. QUOTE
ing a symbol prevents it frombeing evaluated at all, resulting in the symbol itself rather thanthe value of the variable named by that symbol.FUNCTION
alsocircumvents the normal evaluation rule but, instead of preventing thesymbol from being evaluated at all, causes it to be evaluated as thename of a function, just the way it would if it were used as thefunction name in a function call expression.
12There's actually a third, the special operatorMULTIPLE-VALUE-CALL
, but I'll save that for when I discussexpressions that return multiple values in Chapter 20.
13In Common Lisp it's alsopossible to use aLAMBDA
expression as an argument toFUNCALL
(or some other function that takes a function argumentsuch asSORT
orMAPCAR
) with no#'
before it, likethis:
(funcall (lambda (x y) (+ x y)) 2 3)
This is legal and is equivalent to the version with the#'
butfor a tricky reason. HistoricallyLAMBDA
expressions bythemselves weren't expressions that could be evaluated. That isLAMBDA
wasn't the name of a function, macro, or special operator.Rather, a list starting with the symbolLAMBDA
was a specialsyntactic construct that Lisp recognized as a kind of function name.
But if that were still true, then(funcall (lambda (...) ...))
would be illegal becauseFUNCALL
is a function and the normalevaluation rule for a function call would require that theLAMBDA
expression be evaluated. However, late in the ANSI standardizationprocess, in order to make it possible to implement ISLISP, anotherLisp dialect being standardized at the same time, strictly as auser-level compatibility layer on top of Common Lisp, aLAMBDA
macro was defined that expands into a call toFUNCTION
wrappedaround theLAMBDA
expression. In other words, the followingLAMBDA
expression:
(lambda () 42)
expands 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 toFUNCALL
, legal. In other words, it's pure syntactic sugar. Mostfolks either always use#'
beforeLAMBDA
expressions invalue positions or never do. In this book, I always use#'
.