Reputation: 14313
You all know the story: programmer reads other people's code, programmer sees symbol they don't understand, Google fails them because it's difficult to search for non-alphanumeric symbols.
This time it's the @
symbol, which seems to be used to inject the contents of one list into the middle of another. For instance:
`(5 6 7 ,@'(8 9) 10 11)
;=> (5 6 7 8 9 10 11)
I'm comfortable with this usage, but I'm wondering whether I understand the behavior of @
correctly? Does it have other uses? And what causes the error in the following transcript (from CLISP)?
[1]> (list 1 2 3 4 @'(5 6 7))
*** - SYSTEM::READ-EVAL-PRINT: variable @ has no value
Lastly, what exactly is @
? It doesn't seem to be a function:
[3]> (print #'@)
*** - FUNCTION: undefined function @
I'm guessing it's a fundamental syntax like the backquote (`
), or comma (,
). Is this correct? Sorry if this is a duplicate, but once again, as far as I know it's impossible to search for @
.
Upvotes: 21
Views: 3997
Reputation: 114461
,@
should be considered a single entity, and the meaning of ,@
is that the following expressions is spliced into the current quasi-quoted list.
For example you cannot use
`,@x
because the quasi-quoted expression is not a list and ,@
requires a list to be spliced to.
Similarly (in my reading of the standard) you cannot use
`(list ,@5)
because 5
is not a list (however both SBCL and CLISP allow it and expand to (list . 5)
).
Actually the behavior of SBCL and CLISP is acceptable, but it would also be acceptable for a compliant implementation to give an error if ,@
is used with a non-list argument.
CLHS section 2.4.6 last possible expansion for `((,a b) ,c ,@d)
shows that raising an error for a non-list could be acceptable too.
Upvotes: 6
Reputation: 85813
It's described in the HyperSpec in the section on backquote:
2.4.6 Backquote
If a comma is immediately followed by an at-sign, then the form following the at-sign is evaluated to produce a list of objects. These objects are then “spliced” into place in the template. For example, if
x
has the value(a b c)
, then`(x ,x ,@x foo ,(cadr x) bar ,(cdr x) baz ,@(cdr x)) => (x (a b c) a b c foo b bar (b c) baz b c)
It's worth noting that ,@
isn't always necessary; according to the same documentation:
Anywhere “,@” may be used, the syntax “,.” may be used instead to indicate that it is permissible to operate destructively on the list structure produced by the form following the “,.” (in effect, to use nconc instead of append).
Your intuition is mostly correct when you ask, "so basically @ on its own means nothing and the only real operator is ,@?" @
can be used in other places as a normal letter. That's why you get the error that you mentioned: (list 1 2 3 4 @'(5 6 7))
is simply
(list 1 2 3 4 @ '(5 6 7))
and @
is a variable, but it doesn't have a value here. Compare that with:
(let ((@ 4.5))
(list 1 2 3 4 @ '(5 6 7)))
;=> (1 2 3 4 4.5 (5 6 7))
Sorry if this is a duplicate, but once again, as far as I know it's impossible to search for "@".
Searching for documentation on certain non-alphanumeric characters can be difficult, but I've found a few techniques that can help. E.g., if you go to lispdoc.com, you can search for comma
, and the results there will get you headed toward backquote. (Searching for at-sign didn't help though.) That's not a perfect solution, but it can help sometimes.
Upvotes: 20
Reputation: 452
Comma-at is for list splicing in CL. It places the list content into the expression containing it, removing the list's outermost parantheses. Paul Graham's now freely available book "On Lisp" contains many more details about it, if my mind serves me right, and is a good read anyway if you want to learn more about advanced Lisp.
Upvotes: 1