Lisp parenthesis question
Asked Answered
H

6

8

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 don'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.

Hight answered 8/5, 2011 at 1:52 Comment(2)
can you be confusing the operator precedence changing parenthesis with the list defining parethesis in lisp? i.e (2+3)*5 vs (a,b,c,d)?? Meaning, the function is waiting for a list of list as its second parameter, but if you remove the parenthesis it will be only a list.Azov
@Azov - there are no operator precedence affecting parens in lisp all operations are 100% unambiguous as all operations must be fully parenthesized (2+3)*5 would be written (* (+ 2 3) 5) in lispMalia
D
11

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.

Dukie answered 8/5, 2011 at 2:20 Comment(0)
M
7

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.

Monoicous answered 8/5, 2011 at 2:54 Comment(3)
You're right 99.9% of the time, but I think there are a couple obscure cases where parentheses are actually optional in CL. For example, (defstruct s f) and (defstruct s (f)).Portable
@Ken: Well, parens around f really seem to be optional, but in fact they define a macro with a slightly different behavior: (defstruct s f) defines just slot name and (defstruct s (f)) defines slot name with, possibly, initform and slot options. And in each case number of parens is strictly defined.Monoicous
I can choose to put them there or not -- that's pretty much the definition of "optional". Yep, the number is strictly defined to be either 0 or 1 sets of parens there, which is what make it optional. :-) Not sure what you mean by "possibly, initform and slot options", since I'm not specifying any of those in either case.Portable
C
3

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.

Candelabra answered 8/5, 2011 at 2:17 Comment(0)
B
2

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.

Bolme answered 8/5, 2011 at 6:38 Comment(0)
I
2

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!

Infect answered 8/5, 2011 at 19:57 Comment(0)
M
1

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.

Malia answered 8/5, 2011 at 2:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.