Lisp parenthesis question
This piece of code is from book : "Land Of Lisp" First version is from book. When I read it, i thought there are parenthesis "(" not necessary just before "at-loc-p" at 2nd line and ")" just after loc at 3rd line.
(defun person-at (loc pers per-locs)
(labels ((at-loc-p (pers)
(eq (cadr (assoc pers per-locs)) loc)))
(remove-if-not #'at-loc-p pers)))
But when I test this ,
(defun person-at (loc pers per-locs)
(labels (at-loc-p (pers)
(eq (cadr (assoc pers per-locs)) loc))
(remove-if-not #'at-loc-p pers)))
It came out :
Required arguments in AT-LOC-P do开发者_StackOverflow中文版n't match lambda list (CCL::FUNCNAME CCL::LAMBDA-LIST &BODY CCL::LABELS-FUNCTION-BODY).
[Condition of type CCL::SIMPLE-PROGRAM-ERROR]
I don't quiete understand. Need help. thank you.
The LABELS
in
(defun person-at (loc pers per-locs)
(labels ((at-loc-p (pers)
(eq (cadr (assoc pers per-locs)) loc)))
(remove-if-not #'at-loc-p pers)))
has the syntax labels ((function-name lambda-list [[local-declaration* | local-documentation]] local-form*)*) declaration* form*
, so you will have to provide a list of local function definitions for it to work.
Since those local function definitions are themselves parenthesized, you will have to pass labels
a list of this structure: ((fun1 (...) ...) (fun2 (...) ...) ...)
.
Unfortunately, the stack trace and error message aren't very helpful in spotting the error here, since the message does not tell you that the problem is with labels
, and it also isn't topmost in the trace. The 4: (CCL::NX1-LABELS ...
would be a hint (debugger buffer on my local machine).
Take a look at the documentation for labels
in the Hyperspec to learn more.
In other languages, not Lisps, parenthesis are normally used to group operators and so are optional in many cases. But in Lisp parenthesis are always meaningful. There may not be extra or optional parenthesis.
Most often parenthesis around expression mean function or macro application:
(foo 1)
Two parenthesis at the start of expression in such a case may occur, for example, when the first element of expression is another expression, that is evaluated to a function itself. For instance, imagine function make-adder
, which takes a number and returns another function with partially applied addition (btw, it's an example of currying):
(defun make-adder (number)
(lambda (another-number) (+ number another-number)))
We can create function variable increment
this way, and then apply it to variable:
(defvar increment (make-adder 1))
(increment 5) ; ==> 6
but we can also call it directly (ok, this will not work in Common Lisp, but same syntax works in other Lisps, called "Lisp-1", so I believe it's worth to mention it here) :
((make-adder 1) 5) ; ==> 6
making double parenthesis at the beginning. And, of course, both parenthesis are mandatory.
And one final case, which describes your situation, is when the language or user macro uses list of lists for its purposes (do you still remember, that Lisp program is itself a list of lists of expressions?). For example, defun
knows, that its 1st argument must be a symbol, and its 2nd argument must be a list. And labels
macro knows, that its 1st argument must be a list of definitions, each of which is a list itself. It was made to allow user to define more then one label at a time:
(labels ((definition-1) (definition-2) ...)
(do-this) (do-that) ...)
So, you can see, that each parenthesis mean something and you cannot drop them on your own.
i thought there are parenthesis "(" not necessary
Well they are. You can't just add and remove parentheses as you please and expect it to work any more than you could use the symbol asdklfjhsbf
in place of, say, defun
and expect it to work. You have to give LABELS ((function-name lambda-list forms) ... )
, and that's just the syntax of LABELS; if you don't follow it the compiler will raise an error.
Parentheses are significant and essential in Lisp. Now you may understand why the Land of Lisp music video says: "I eat parentheses for breakfast... And if my program isn't done I eat parantheses for lunch... They might look funny but they have semantic power... That gives your programs lots of brevity and punch. Soon you'll have dreams about them too!
Indeed there are a few places where panthesis are sort of "unnatural" in Lisp. Normally the rules are very consistent: a parenthesis starts a list and the first element of a list is the function to be used with all remaining list elements as parameters. This consistency is also maintained for most macros and special forms and this makes Lisp code very uniform... however in some macro and special operator parenthesis have a differnt meaning and are used for grouping... for example
(dolist (x L) (print x))
in this case for example x
in the first panthesis is NOT the function to be called passing L
as argument. Another example is
(let ((x 10)
(y 20))
(print (+ x y)))
In this case parenthesis are used just for grouping and the first element (x 10)
is clearly not the function to be applied nor is its first element x
a function either.
labels
works exactly like let
and the apparently "extra" parenthesis is needed for grouping in case more tha one function is defined.
While these special cases are indeed somewhat annoying, they're very few and after writing some quantity of Lisp code you'll internalize them and you will just get them right without thinking.
They are none the less asymmetries that for example make quite hard to write a correct code walker and also often when you make a mistake in this "syntax area" of Lisp unfortunately the error message is not really helpful in pointing you to the error.
This "complexity" is of course just nothing compared to other languages (and let's not start discussing how clear are messages when you make a mistake in a C++ template ;-) ).
I think that is not completely true that Lisp syntax is "trivial" or even just absent. Lisp syntax is present even if not at character level but at Lisp forms level, and it's almost trivial with the exclusion of an handful of special forms and macros.
As @danlei said there must be a list of function definitions in the first part of a let
/labels
/flet
. if it is a single element then you end up with those redundant-looking double parentheses.
精彩评论