Macros 公共Lisp双反引号,反引号,引号,反引号序列?

Macros 公共Lisp双反引号,反引号,引号,反引号序列?,macros,lisp,common-lisp,Macros,Lisp,Common Lisp,我正在阅读《让我超越Lambda》,它涉及一些非常深层次的宏创作。这很吸引人,我主要是设法跟上它 在第4章中,Hoyte为CL-PPCRE匹配和替换函数实现了读卡器宏,以便您可以执行以下操作: (#~m/(foo|bar)\d+/ "Some foo99") ; matches! (#~s/foo(\d+)/bar\1/, "Some foo99") ; "Some bar99 为了实现这一点,我们定义了一个使用双反引号的宏,因为它实际上是由包装器宏展开的,包装器宏需要带引号的值(它返回

我正在阅读《让我超越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)
因此:

  • 双引号,形式完全扩展
  • 单引号,形式不展开
  • 不带逗号的引号,表单完全展开,结果带引号

在评估双反引号表单时,首先处理内部反引号,结果是单反引号表单。在计算内部后引号表单时,只计算两个逗号前的元素。但是,计算这些双引号元素的结果仍然是(单引号)未引号的,因此,当计算得到的单引号形式时,将再次对其进行计算。要仅在内部反引号形式中实现评估,必须插入普通引号,从而导致
,',

看看如何

(let ((tmp (gensym)))
    ``(lambda (,tmp ,,tmp ,',tmp) ()))
评估为

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

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

您最后的defmacro引用了
str
。这是怎么一回事?它的定义是什么?你能演示一下如何调用
pcre/match lambda form
吗?啊,这需要一些解释,因为实际上有很多层宏在进行。这本书是推动宏创作的边界(为了乐趣和教育)
str
是一个由一个封闭的
LET
定义的符号,它表示一个可以安全使用的变量名。
pcre/match lambda form
这样叫:
(pcre/match lambda form'(“foo”)
,其中
“foo”
已经被处理
#~m/foo/
格式字符串的流读取器读取。我正在以打印格式读取它,但它(部分)也可以在线获取:这里没有对错。根据:如果替代形式F2的副作用行为也与上述描述一致,则实现可以自由地将后引形式F1解释为任何形式F2,在评估时,将产生与上述定义所暗示的结果相同或相等的结果。也就是说,在进行任何比较之前,必须对表格进行全面评估。哇,这有点复杂。我现在只是在玩一些基本的双反引号和那些不同的反引号,看看在每种情况下会发生什么。我现在明白了,谢谢:)@d11wtq您可能还想看看“Common Lisp the Language”的附录C(backquote),该附录包含一个示例实现和backquote语法示例。