Common Lisp中的反引号:读取和求值

5
这个问题与这个这个Elisp问题有些相关。基本上,反引号是如何被读取和评估的?会发生什么样的进程?标准是否有任何说明?
这是我所期望的,但并不会发生:符号`是一个读取宏,被转换成某种(BACKQUOTE ...)宏/特殊形式(类似于'被转换为(QUOTE ...))。这并没有发生,事实上,Common Lisp甚至没有BACKQUOTE宏。
正在发生什么(SBCL):
CL-USER> (defparameter *q* (read-from-string "`(a b ,c)"))
*Q*
CL-USER> *q*
`(A B ,C)
CL-USER> (car *q*)
SB-INT:QUASIQUOTE
CL-USER> (cdr *q*)
((A B ,C))

虽然与预期不同,但没关系。现在,C本身是一个有趣的动物:

CL-USER> (type-of (third (cadr *q*)))
SB-IMPL::COMMA

如果没有逗号符号,评估读取表达式就可以了。
CL-USER> (eval (read-from-string "`(a b c)"))
(A B C)

但是,如果我想要使用本地绑定来评估原始表达式,即使对于 C,也存在问题:

(let ((c 10)) (eval (read-from-string "`(a b ,c)")))
; in: LET ((C 10))
;     (LET ((C 10))
;       (EVAL (READ-FROM-STRING "`(a b ,c)")))
; 
; caught STYLE-WARNING:
;   The variable C is defined but never used.
; 
; compilation unit finished
;   caught 1 STYLE-WARNING condition
; Evaluation aborted on #<UNBOUND-VARIABLE C {1007A3B2F3}>.

这意味着 EVAL 没有捕获到绑定了 C 的环境。
PS. 有趣的是,在 Elisp 中这个方法可以运行。

@RainerJoswig,“标准宏字符”和“读取器宏”是同一件事情吗?还是我对它们感到困惑? - mobiuseng
1
“标准宏字符”指的是由标准定义的宏字符。CLHS词汇表中,宏字符n.是指当Lisp阅读器在其主分派循环中遇到的字符,引入了一个阅读器宏。 - Rainer Joswig
2
关于技术细节,您还可以查看您的实现如何操作quasiquotes以及Faré quasiquotes - coredump
1个回答

14

反引号

反引号是Common Lisp中的标准宏字符

在Common Lisp中,反引号表达式的表示是未定义的。不同的实现使用不同的表示方法。对于SBCL,所看到的内容是特定于实现的。

EVAL

您在eval中遇到的问题与读取器或反引号表达式完全无关:

? (let ((c 10))
    (eval '(list 'a 'b c)))

Error: The variable C is unbound.
在Common Lisp中,EVAL使用动态环境和空词法环境来评估形式。上述词法环境(其中c绑定到10)不会被使用。
但是动态绑定是需要的。我们需要声明这个变量是special的:
? (let ((c 10))
    (declare (special c))
    (eval '(list 'a 'b c)))
(A B 10)

这样也可以运作:

? (let ((c 10))
    (declare (special c))
    (eval (read-from-string "`(a b ,c)")))
(A B 10)

Emacs Lisp默认使用动态绑定(尽管GNU Emacs现在也支持词法绑定)。Common Lisp默认使用词法绑定。


我不知道EVAL使用空词法环境。谢谢! - mobiuseng

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