Macros 为什么在宏定义中需要@符号?

Macros 为什么在宏定义中需要@符号?,macros,lisp,common-lisp,quasiquotes,Macros,Lisp,Common Lisp,Quasiquotes,在以下宏中时: (defmacro when (condition &rest body) `(if ,condition (progn ,@body))) 为什么会有一个“at”@符号?在准连续段中插入计算值时,有两个运算符: “逗号”运算符, “逗号拼接”运算符,@ 逗号,在准引号的sexpr中插入以下表达式的值,而逗号拼接需要表达式follow is a list,只能在准引号的列表中使用:其效果是将表达式的所有元素插入准引号的列表中运算符出现的位置 通过做一个小实验很容

在以下
宏中
时:

(defmacro when (condition &rest body)
  `(if ,condition (progn ,@body)))

为什么会有一个“at”
@
符号?

在准连续段中插入计算值时,有两个运算符:

  • “逗号”运算符
  • “逗号拼接”运算符
    ,@
逗号
在准引号的sexpr中插入以下表达式的值,而逗号拼接需要表达式follow is a list,只能在准引号的列表中使用:其效果是将表达式的所有元素插入准引号的列表中运算符出现的位置

通过做一个小实验很容易看出差别

> (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)
正如您可以看到的那样,@将列表中的元素直接放在展开中。如果没有,您将获得放在扩展中的列表

在执行替换时,将@与不产生列表的表达式一起使用将是错误的:

* (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] 

@
还可以考虑解构列表并将其附加到中显示的列表中,如中所述

`(a,@(列表12)c)
相当于:

(append (list 'a) (list 1 2) (list 'c)) 
产生:

(a 1 2 c)

该宏定义相当于

(defmacro when (condition &rest body) 
  (list 'if condition (cons 'progn body)))
(defmacro when (condition &rest body) 
  (list 'if condition (list 'progn body)))
但是如果没有
@
,它将相当于

(defmacro when (condition &rest body) 
  (list 'if condition (cons 'progn body)))
(defmacro when (condition &rest body) 
  (list 'if condition (list 'progn body)))
由于
body
是一个列表,这将导致对其进行评估,就像括号中的函数调用一样,例如
(当t123时)
将扩展为

(if t (progn (1 2 3)))
而不是正确的

(if t (progn 1 2 3))

请注意,导致扩展的不是
@x
,而是
,@x
正确。。。固定的