comma-comma-at in Common Lisp
Asked Answered
T

1

4

I am confused about how comma-comma-at does what it does.

An example of use of comma-comma-at is in Is there a use for double unquote (double comma) when defining a Lisp macro?

It seems to me that

(let ((parms '(x y)))
  ``(beg ,,@parms end))

expands to or something equivalent to

`(beg ,x ,y end)

How does it expands to that?

I was thinking, if I evaluate the double backquote form, it causes the second comma to do its work, and the result is:

`(beg ,<splice stuff here> end)

and it looks like Lisp interpreter should complain and say "I don't know what it means to splice stuff before a comma" in the sense that when Lisp encounters

`,@abc

it would be likely to say "I don't know what it means to splice stuff before a backquote. Don't ever do that again."

But somehow, the interpreter does not complain and simply choose to do

`(beg <splice stuff here and write comma in front of each of them> end)

Is that compatible with rules in CLHS backquote?


For readers information, comments following the answer refer to an old version of the answer, and lead to update of the answer. New readers don't need to read the comments.


Also see CHLS "innermost backquoted form should be expanded first" meaning

Torchwood answered 30/7, 2013 at 21:6 Comment(1)
+1 for asking a LISP question...Furlough
U
5

CLHS states: "If the backquote syntax is nested, the innermost backquoted form should be expanded first. This means that if several commas occur in a row, the leftmost one belongs to the innermost backquote."

So, the first comma unquotes the second backquote; the ,@ then splices in the contents of parms, as all quotes have been undone. Unquoting does not "replace" forms in steps as you describe - the commas just back up in the structure of backquoted forms when deciding how to evaluate the contained forms.

(let ((parms '(x y)))
  `(list 'beg ,@parms 'end))

obviously evaluates to (list 'beg x y 'end), which is what you are after here; producing a form that creates the desired structure as its output. The additional outer backquote is simply a shorthand for this syntax, in the same manner as '(foo bar) is (equality issues aside) a shorthand for (list 'foo 'bar).

Unni answered 30/7, 2013 at 21:24 Comment(6)
In CLISP, (let ((parms '(x y))) ``(beg ,,parms end)) (=A) evaluates to (CONS 'BEG (CONS (X Y) '(END))) (=B1) which is different from '(beg (x y) end) (=B2). B1 and B2 are different in that evaluation of B1 results in error, while evaluation of B2 result in (BEG (X Y) END) without error. And (let ((parms '(x y))) ``(beg ,,@parms end)) (=P) and (let ((parms '(x y))) `'(beg ,@parms end)) (=Q) seem different in that double evaluation of P results in error while double evaluation of Q does not.Torchwood
@JisangYoo: No, (cons 'beg (cons (x y) '(end))) is the same as '(beg (x y) end), in the sense that it evaluates to the same form (beg (x y) end). This was the sense I meant when I said "to something along the lines of" and not simply "to".Unni
But (cons 'beg (cons (x y) '(end))) does not evaluate to (beg (x y) end) because (x y) is not quoted.Torchwood
SBCL seems to give results easier to reason. In SBCL, A evaluates to `(BEG ,(X Y) END) (=B0). B0 is equivalent to B1, the CLISP result, but neither B0 nor B1 is equivalent to B2.Torchwood
Sorry, this is true. My last edit was a step in the wrong direction. I'm primarily using ccl, and it evaluates A into (LIST* 'BEG (LIST* (X Y) '(END))) - I didn't realize there was no quote for (X Y). However, the pre-edit version, with which I replaced the answer now, should be correct.Unni
Also figured out a rationale from a bit different perspective, which now makes sense at least to me :)Unni

© 2022 - 2024 — McMap. All rights reserved.