Common Lisp 中 comma-comma-at的答案
帮助我弄清楚发生了什么。我只是要建立在这个答案的基础上并适用于这个问题。
我们在这里有两种推理嵌套反引号形式的方法。一种方法,我称之为替换解释,就是对于双重嵌套的反引号形式,对该形式的评估是
- 删除最外面的反引号字符
- 然后用它们的评估结果替换出现在与最外层反引号相同级别的逗号后面的形式(请参阅使用两个反引号和逗号,Common Lisp以获得相同级别的含义)(另外,删除那些逗号)
- 然后通过将它们的评估结果拼接到它们的位置来替换出现在与最外层反引号相同级别的逗号形式(另外,删除那些逗号)
另一种方式,我将称之为等价解释,是我应该用等效的非反引号形式重新解释反引号形式,就像在 CLHS 链接中一样,对于双重嵌套的反引号形式,我应该在之前重新解释最里面的反引号形式重新解释最外层的反引号形式。
替换解释唯一明确指定的是如何评估反引号形式。反引号形式如何等同于非反引号形式只是间接指定为它们的评估如何工作的结果。
等效解释唯一明确指定的是反引号形式如何等效于非反引号形式。反引号表单如何被评估只是间接指定为它们等效的非反引号表单如何评估的结果。
SBCL 评估表达式 P 的方式很容易从替换解释中得到解释。但也可以从等价解释来解释。要了解原因,我们首先研究示例 A 和示例 B。
一些约定:我用 ~ 来表示“前一个表达式等同于下一个表达式”。我用 ~> 来表示“前一个表达式的计算结果等于或等于下一个表达式”。“等同于”我的意思是“可能被解释为”,就像在 CLHS 链接中一样。
示例 A(一个简单的反引号形式):
`(open ,@(list 'cat 'dog))
;; ~
(append (list `open)
(list 'cat 'dog)
nil)
;; ~
(append (list 'open)
(list 'cat 'dog)
nil)
;; ~>
(open cat dog)
示例 B(当 comma-at 位于更深的位置时):
`(beg (open ,@(list 'cat 'dog)))
;; ~
(append (list `beg)
(list `(open ,@(list 'cat 'dog)))
nil)
;; ~>
(beg (open cat dog))
示例 C(表达式 P)
`(outer
`(inner ,@(no ,@(list 'cat 'dog))))
;; ~
`(outer
'(append
(list `inner)
(no ,@(list 'cat 'dog))
nil))
;; ~>
(outer
'(append
(list `inner)
(no cat dog)
nil))
;; ~
(outer
`(inner ,@(no cat dog)))
因此,替代解释与迄今为止的等价解释是一致的。
这两种解释是否完全兼容?替换解释有一些复杂性,如果我正确阅读 CLHS 链接,等效解释似乎是 CLHS 的一部分。因此,等效解释似乎是真正的交易,而替代解释只是一种方便的错觉。
替代解释的并发症是什么?我已经通过替换解释浏览了反引号附录 C中的所有双重嵌套反引号示例,并且大多数示例(除了四个示例)没有显示任何复杂性。对于大多数示例,替换解释有效并且与实际结果一致。
您遇到并发症的四个例子是:
,@',@
,',@
,,@
,@,@
对于前两个,复杂之处在于您必须在引号字符之前拼接一个列表。在引号字符之前拼接是什么意思?这不代表任何意思。但是如果你认为'something
as (quote something)
,那么你可以说在引号字符之前拼接单个元素列表是有意义的,并且它意味着引用该单个元素。如果您像这样修补替换解释,那么它会给出与实际结果一致的结果。
对于最后两个,复杂之处在于您必须在逗号字符(或逗号-at)之前拼接一个列表。在逗号字符前拼接是什么意思?这不代表任何意思。但是如果你说“让它意味着简单地拼接一个列表,然后在每个插入的元素前面放一个逗号(或逗号)”,那么这种修补替换解释给出的结果与实际结果一致。
Emacs Lisp 注意:对于最后两个,Emacs Lisp 和 Common Lisp 给出不同的结果。
常见的 Lisp 实现 注意:对于 comma-quote-comma-at,不同的实现会根据这个线程给出不同的结果
我会远离在我的代码中使用这四种情况中的任何一种。