我正在阅读《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)
因此:
- 双引号未被引用时,表单已完全展开。
- 单引号未被引用时,表单未被展开。
- 带逗号的未引用形式,表单已完全展开且结果被引用。
str
是由封闭的LET
定义的符号,表示一个安全使用的变量名。 - d11wtqpcre/match-lambda-form
的调用方式如下:(pcre/match-lambda-form '("foo"))
,其中"foo"
是由处理形如#~m/foo/
的字符串的流读取器读取的。 - d11wtqdefmacro!
的定义,它使用了defmacro/g!
,而defmacro/g!
又使用了...(你懂的) :)。请访问http://letoverlambda.com/index.cl/guest/chap4.html#sec_4。 - d11wtq