我正在阅读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)
所以:
答案 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"