eBackquote in Common Lisp: read and eval



这个问题在某种程度上被重新定位为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的环境。

有趣的是,在 Elisp 中,这是有效的。

反引号

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

在Common Lisp中,反引号表达式的表示是未定义的。实现实际上使用不同的表示形式。您看到的 SBCL 是特定于实现的。

评估

您在 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 默认具有词法绑定。

最新更新