I am trying to learn Common Lisp with the book Common Lisp: A gentle introduction to Symbolic Computation. In addition, I am using SBCL, Emacs and Slime.
In chapter 7, the author suggests the following about lambda expressions
:
This confuses me because the SBCL's REPL returns:
CL-USER> #'lambda
#<CLOSURE (:MACRO LAMBDA) {1000D736DB}>
Apparently, the author used Lisp Works (not 100% sure). I think this is not relevant to the difference described above. However, I thought it would be better to mention it anyway.
My SBCL's REPL also returns macro
for the well-known macros such as and
:
CL-USER> #'and
#<CLOSURE (:MACRO AND) {1000D7365B}>
Note that the behavior with "ordinary" functions such as append
is different:
CL-USER> #'append
#<FUNCTION APPEND>
This post here seems to slightly touch the non-single nature of lambda expressions. However, it does not mention anything about markers.
Did I miss something about the nature of lambda expressions?
A way of thinking about this is to realise that the only way to get at a lexically-apparent function value in CL is the special operator
function
: if you want to get at the function associated withfoo
in the current lexical environment you have to say(function foo)
:For instance. So
function
is the special operator which lets you see what is in the function namespace.function
has some syntactic sugar, which is#'
, in the same wayquote
does (I'm not going to use this below). You can think of function application(f x y)
as approximately like(<funcall> (function f) x y)
, where<funcall>
is some magic thing which does not in turn get replaced like that.But you also want anonymous functions, and, well, you use
function
for that as well, with its argument being a lambda expression:So an anonymous function is denoted as
(function (lambda (...) ...))
. You could, if you like, think of(lambda (...) ...)
as the 'name' of a function. (People I think don't like this because it interferes with the idea of anonymous functions, but it's pretty clear that there is a countable set of possible function 'names' of the form(lambda (...) ...)
and you could even enumerate this set I think (doing so would be fiddly in the same way that enumerating the rationals is fiddly).Since the function position in a function application is already interpreted in the namespace of functions,
((lambda (...) ...) ...)
denotes an anonymous function application: it's more-or-less the same as(funcall (function (lambda (...) ...) ...)
(see CLHS again).And this is how CL was at some point in the 1980s.
There is then some historical confusion which I am unsure of: I remember it happening but I don't remember the ordering. First of all, in a Lisp-1 you don't need any of this
function
stuff: the formcar
denotes the function which gets the car of a cons, you don't need to say(function car)
. And similarly(lambda (...) ...)
denotes a function. As well as this there was/is another proposed Lisp standard, which was/is ISLisp, which may be here. And although ISLisp isn't a Lisp-1, it does have a form(lambda (...) ...)
which denotes a function.People wanted CL to be able to be compatible with ISLisp, which means that
(lambda (...) ...)
should denote a function. What everyone actually did was to secretly add a definition like:But, critically, you can't portably do that in CL, because
lambda
iscl:lambda
and you're not allowed to redefine things in the CL package. People did it anyway but the result was that their programs were not portable, and often had to be decorated with special magic to unlock & relock theCL
package.Well, the solution to that was that the language has to provide such a macro. And sometime between the language defined by CLtL1 and the final standard this happened, so now
lambda
has a macro definition whose expansion is (more-or-less: implementations may be allowed to do special things) the obvious expansion:So in modern CL:
lambda
denotes ('names') a function in a form like(function (lambda (...) ...)
and also in the function position of a form, so((lambda (x) x) 1)
, say.lambda
is defined as a macro which expands to(function (lambda (...) ...))
which makes it easier to use.Notes: the implementation you are using is, I think, allowed to do what it does for macros, but you should not rely on this:
You should really use
macro-function
which will tell you if something has a macro definition.