Common Lisp Double-Backquote,Unquote,Quote,Unquote sequence?

时间:2013-07-02 15:23:46

标签: macros lisp common-lisp

我正在阅读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)

所以:

  • 双重未引用,表格完全展开。
  • 单一 - 不加引号,表格不会扩展。
  • 不加引号,表格完全展开,结果引用。

2 个答案:

答案 0 :(得分:12)

在评估双重反引号形式期间,首先处理内部反引号,结果是单一反引号形式。在评估内部反引号形式期间,仅评估前面有两个逗号的元素。然而,评估这些双重未引用元素的结果仍然(单独)不加引号,因此在评估得到的单一反引号形式时再次对其进行评估。要仅在内部反引号形式中进行评估,必须插入普通引号,结果为,',

了解如何

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

评估为

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

答案 1 :(得分:2)

','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"