这个反引号 "syntax" 在 lisp 中是如何工作的?

How this backquote "syntax" works in lisp?

这里是 Paul Graham 的 On Lisp 一书中的简化示例(类似于语法的方案)。

(define-macro (bar)
  (let ((x 10) (y '(1 2 3)) (z 'foo))
    `(list ,x `(,',z ,,@y))))

我知道 ,,@y 应该如何工作,但不确定 ,',z 应该如何工作 应该首先评估什么以及以什么顺序评估。 (我知道它应该评估为符号 foo,因为它 return (10 (foo 1 2 3)) 诡计多端,但我不确定确切的步骤是什么)。

我在 JavaScript 的 lisp 中需要这个,结果是:

(10 ((unquote z) 1 2 3))

因为它只是从左到右评估它(我只处理特殊的 ,, 和更多逗号)。你应该如何评估这个表达式。

书上也有这个例子:

(defmacro propmacro (propname)
   `(defmacro ,propname (obj)
       `(get ,obj ',',propname)))

',',应该如何评价?这种情况下的步骤是什么?

backquote/quasiquote还有其他奇怪的边缘情况吗?你能举出这些例子吗?应该如何评估它们,按什么顺序评估?

,',z 的工作原理是:

`(list ,x `(,',z ,,@y))))
          ^ ^
          |  `- this comma
           `- belongs to this backquote

上面的逗号将表达式 ',z(quote ,z) 插入到内部反引号中。而 ,z 又属于外部反引号。

因此z的值被插入到(quote ,z)中使得(quote <value-of-z>).

然后,实际上,内部反引号的行为类似于 `(,'<value-of-z>)

具体来说,假设 z 包含列表 (+ 2 2)。那么我们可以理解为外部反引号将 (+ 2 2) 插入内部反引号以产生 `(,'(+ 2 2) ...)。这现在很容易理解:当内部反引号被评估时, (+ 2 2) 被保护免于评估,导致对象 ((+ 2 2) ...).

模式 ,',',', ... ,',expr 用于在最外层反引号的评估期间获得 expr 的单个评估,这样该值然后通过剩余反引号的任意数量的评估轮传播嵌套而无需进行进一步评估。这里有一种 "backquote algebra" 在起作用,其中 "commas and quotes cancel out".

您还可以将 ,',','... 想象成一种钻头,它可以挖掘嵌套层,让您可以在结构的任何位置植入文字值。例如

(defmacro super-nested-macro (arg)
  `(... `(.... `(.....`(we simply want arg down here ,',',',arg)))))

super-nested-macro 的作者只是想将 arg 的值粘贴到模板中,位于埋在其他三个反引号中的位置。因此通常的 ,arg 不能使用:那个逗号会被误解为属于 inner-most 反引号。

Are there any other weird edge cases with backquote/quasiquote?

反引号中的一个奇怪边缘案例试图拼接成一个点位置:

`(a b c . ,@foo)  ;; not allowed

`(a b c . ,foo)   ;; OK: equivalent to `(a b c ,@foo)

不确定各种实现如何处理点位置的反引号:

`(a b c . `(d e f))

这真的没有意义,我怀疑获得的实际结果将取决于反引号实现内部。

并非所有对象都被遍历以取消引用:

 `#c(,(sin theta) ,(cos theta)) ;; Not required by ANSI CL, oops!

这可以通过实现的扩展来实现。