这个反引号“语法”如何在Lisp中起作用?

时间:2019-06-04 06:56:49

标签: macros lisp common-lisp lisp-macros

这是保罗·格雷厄姆(Paul Graham)的《论Lisp》一书的简化示例(类似于语法)。

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

我知道,,@y应该如何工作,但是不确定,',z应该如何工作,应该首先评估什么,以什么顺序进行评估。 (我知道它应该评估为foo符号,因为它以guile形式返回(10 (foo 1 2 3)),但是我不确定确切的步骤是什么。)

我需要用JavaScript来获得结果,这是我需要的:

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

因为它只是评估它从左到右的形式(我只在专门处理,,和更多逗号)。您应该如何评估此表达式。

书中也有这个例子:

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

应该如何评估',',?在这种情况下应采取什么步骤?

还有其他带有反引号/准引号的怪异情况吗?您能否显示这些示例以及应如何评估它们以及以什么顺序进行示例?

1 个答案:

答案 0 :(得分:6)

,',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的单个求值,这样该值就可以传播通过剩余反引号嵌套的任何数量的评估回合而不会正在接受进一步评估。这里有一种“反引号代数”,其中“逗号和引号被抵消”。

您还可以将,',','...可视化为一种钻头,它在嵌套的各个层中进行挖掘,以使您可以在结构中的任何位置植入字面值。例如

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

super-nested-macro的作者只是想将arg的值粘贴到模板中,该位置被埋在其他三个反引号中。因此无法使用通常的,arg:逗号将被误解为属于最里面的反引号。

  

还有其他带有反引号/准引号的怪异情况吗?

反引号中一种奇怪的边缘情况试图将其拼接到点位置:

`(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!

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