In the following when
macro:
(defmacro when (condition &rest body)
`(if ,condition (progn ,@body)))
Why is there an "at" @
sign?
The double-number-sign or token-pasting operator (##), which is sometimes called the merging or combining operator, is used in both object-like and function-like macros. It permits separate tokens to be joined into a single token, and therefore, can't be the first or last token in the macro definition.
The #define creates a macro, which is the association of an identifier or parameterized identifier with a token string. After the macro is defined, the compiler can substitute the token string for each occurrence of the identifier in the source file.
SC26-4940-06. A macro definition is a named sequence of statements you can call with a macro instruction. When it is called, the assembler processes and normally generates assembler language statements from the definition into the source module.
Macro represents a group of commonly used statements in the source programming language. Macro Processor replaces each macro instruction with the corresponding group of source language statements. This is known as the expansion of macros.
The @
can also be thought of deconstructing the list and appending it to the list appears in as described in Practical Common Lisp.
`(a ,@(list 1 2) c)
is the equivalent of:
(append (list 'a) (list 1 2) (list 'c))
which produces:
(a 1 2 c)
When inserting computed values in quasiquoted section there are two operators:
,
,@
Comma ,
inserts the value of following expression in the quasi-quoted sexpr, comma-splice instead requires the expression following is a list and can be used only inside a quasi-quoted list: the effect is inserting all elements of the expression in the quasi-quoted list in the position where the operator appears.
It's very easy to see the difference by making a little experiment
> (let ((x '(1 2 3 4))) `(this is an example ,x of expansion))
(THIS IS AN EXAMPLE (1 2 3 4) OF EXPANSION)
> (let ((x '(1 2 3 4))) `(this is an example ,@x of expansion))
(THIS IS AN EXAMPLE 1 2 3 4 OF EXPANSION)
As you can see the use of ,@
will place the elements of the list directly inside in the expansion. Without you get instead the list placed in the expansion.
Using ,@
with an expression that doesn't result in a list will be an error when the substitution is performed:
* (defun f (x) `(here ,@x we go))
F
* (f '(1 2 3))
(HERE 1 2 3 WE GO)
* (f '99)
debugger invoked on a TYPE-ERROR in thread
#<THREAD "main thread" RUNNING {10009F80D3}>:
The value
99
is not of type
LIST
when binding SB-IMPL::X
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.
(SB-IMPL::APPEND2 99 (WE GO)) [external]
0]
Using ,@
not inside a list is instead an error when the quasi-quoted section is analyzed:
* (defun g (x) `,@x)
debugger invoked on a SB-INT:SIMPLE-READER-ERROR in thread
#<THREAD "main thread" RUNNING {10009F80D3}>:
`,@X is not a well-formed backquote expression
Stream: #<SYNONYM-STREAM :SYMBOL SB-SYS:*STDIN* {10000279E3}>
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.
(SB-IMPL::BACKQUOTE-CHARMACRO #<SYNONYM-STREAM :SYMBOL SB-SYS:*STDIN* {10000279E3}> #<unused argument>)
0]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With