Common Lisp中的双反引号、反引号、引号、反引号序列是什么?

21

我正在阅读《Let Over Lambda》这本书,该书涉及一些非常深层次的宏编写。这很有趣,我大多数时候都能跟上进度。

在第4章中,Hoyte 实现了用于 CL-PPCRE 匹配和替换函数的读取器宏,使您可以执行以下操作:

(#~m/(foo|bar)\d+/ "Some foo99")    ; matches!
(#~s/foo(\d+)/bar\1/, "Some foo99") ; "Some bar99

为了实现这一点,我们定义了一个使用双反引号的宏,因为它实际上是由包装宏扩展的,需要引用的值(它返回lambda形式)。在准引用列表中,有一些使用以下序列,'varname,我无法理解。这里的初始,'是什么作用?
(defmacro! pcre/match-lambda-form (o!args)
  "Expands to a lambda that applies CL-PPCRE:SCAN"
  ``(lambda (,',g!str)
      (cl-ppcre:scan ,(car ,g!args)
                     ,',g!str)))

实际上,为了更加清晰易懂,我建议将其简化为只使用defmacro。其中str是一个符号,而args则是一个列表:

(defmacro pcre/match-lambda-form (args)
  "Expands to a lambda that applies CL-PPCRE:SCAN"
  ``(lambda (,',str)
      (cl-ppcre:scan ,(car ,args)
                     ,',str)))

这些引号基本上是将内部部分双引起来,以便结果可以被两次取消引用?实际上将'str放入扩展形式中,而不仅仅是str

编辑| 感谢Terje D.和在REPL中的一些试验,这基本上就是情况:

(defvar a 42)

(equal ``(,,a)  '(list 42)) ; T
(equal ``(,a)   '(list a))  ; T
(equal ``(,',a) ''(42))     ; T
(equal ``(a)    ''(a))      ; T (obviously)

因此:

  • 双引号未被引用时,表单已完全展开。
  • 单引号未被引用时,表单未被展开。
  • 带逗号的未引用形式,表单已完全展开且结果被引用。

1
哎呀,这需要一些解释,因为实际上有许多层宏。这本书通过宏编写(为了乐趣和教育)推动边界。 str 是由封闭的 LET 定义的符号,表示一个安全使用的变量名。 - d11wtq
1
pcre/match-lambda-form 的调用方式如下:(pcre/match-lambda-form '("foo")),其中 "foo" 是由处理形如 #~m/foo/ 的字符串的流读取器读取的。 - d11wtq
1
我正在阅读它的印刷版,但它也(部分)可以在线获取:http://letoverlambda.com/index.cl/toc - d11wtq
1
你还需要第三章中defmacro!的定义,它使用了defmacro/g!,而defmacro/g!又使用了...(你懂的) :)。请访问http://letoverlambda.com/index.cl/guest/chap4.html#sec_4。 - d11wtq
3
这里没有对错之分。根据Hyperspec,2.4.6节(反引号):_实现可以将反引号形式F1解释为任何形式F2,只要在等于下产生的结果与上述定义所暗示的结果相同,并且替代形式F2的副作用行为也符合上述描述。_即必须在进行任何比较之前完全评估这些形式。 - Terje D.
显示剩余7条评论
2个回答

15

在评估双反引号表达式时,首先处理内部的反引号,并且结果是一个单个的反引号表达式。在评估内部反引号表达式时,仅评估由两个逗号引导的元素。但是,评估这些双重未引用元素的结果仍然是(单独的)未引用形式,因此在评估生成的单反引号表达式时再次进行评估。为了仅在内部反引号表达式中进行评估,必须插入普通引号,从而得到 ,',

看看怎么做

(let ((tmp (gensym)))
    ``(lambda (,tmp ,,tmp ,',tmp) ()))

评估为

`(LAMBDA (,TMP ,#:G42 #:G42) nil)

1
哇,这有点复杂。我现在只是玩弄一些基本的双引号和反引号以及它们的变体,看看每种情况下会发生什么。我现在明白了,谢谢 :) - d11wtq
2
@d11wtq 你可能还想看一下《通用Lisp语言》附录C(反引号),该书可在http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node1.html上获得,其中包含反引号语法的示例实现和示例。 - Terje D.

3

这个',X技巧被用来保护X不被再次评估。

看看如何使用:

     (setq a 'fn)
     (let ((x 'a)) ``(,,x ,',x)) ==>  `(,a a) ==> (fn a)

     ;; ``,',X ==> `,(quote "the value of X") ==> "the value of X"

     ;; ``,,X  ==> `,"the value of X" ==> "the value of the value of X"

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