使用两个反引号和逗号,Common Lisp

20

我正在学习common lisp,但是我不理解两个反引号和两个逗号一起使用的用法:

``(a ,,(+ 1 2))

我的意思是,我不知道为什么它会被评估为:

`(A ,3)

不是像那样的东西:

`(A 3)

我自己解释,两个逗号都被用于评估表单前面的两个反引号,所以没有逗号应该留下,但是仍然有一个逗号。这个逗号是什么意思?

``(a ,,(+ 1 2))

仅使用列表和“?”

2个回答

27

规范说明

这是 Common Lisp HyperSpec 关于嵌套的 反引号 的说明:

如果反引号语法被嵌套,则应首先展开最内层的反引号形式。这意味着如果有多个逗号连续出现,则最左边的逗号属于最内层的反引号。

R5RS Scheme 规范也包括了关于 反引号 的详细信息:

准引用表单可以嵌套。只有在与最外层反引号处于相同的嵌套级别上的未引用成分才进行替换。嵌套级别在每个连续的准引用中增加一次,在每个取消引用中减少一次。

还要记住,每次评估只会折叠一个反引号,就像常规引号一样,它不是递归的。

规则实例

为了看到这三个细节如何相互作用,让我们扩展一下你的例子。这个表达式...

``(a ,,(+ 1 2) ,(+ 3 4))

转换成SBCL表示的结果如下:

`(A ,3 ,(+ 3 4))
  1. 左侧的反引号被折叠了,所以(+ 1 2)被第二个逗号(根据HyperSpec)匹配而转义。
  2. 另一方面,(+ 3 4)没有足够的逗号可以扩展(这是R5RS提到的内容)。
  3. 只有一个反引号被折叠了,因为反引号不会被递归地扩展。

扩展两个逗号

为了去掉另一个反引号,需要进行另一层求值:

(eval ``(a ,,(+ 1 2) ,(+ 3 4)))

两个反引号都被删除了,最后我们只剩下一个普通列表:

(A 3 7)

感谢您进一步举例说明了一个更为“病态”的情况(我认为这很棒,而不是病态)。 - Charlie Flowers
此外,要了解“内部反引号形式应首先展开”和“规则实施”的关系,请参见https://dev59.com/y3XYa4cB1Zd3GeqP3TP5。 - Jisang Yoo

2

不,两个逗号都被使用了。有两个引用级别和两个逗号级别。现在只剩下一个引用级别和一个逗号级别。实际上,GNU Common Lisp (2.44.1)将您的表达式评估为

(list 'a 3)

这与...完全相同。

`(a ,3)

但更明确的是“评估”了两个逗号。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接