macros - Common Lisp Double-Backquote, Unquote, Quote, Unquote 序列?

标签 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)

所以:

  • 不加双引号,形式已完全展开。
  • 单引号,形式不展开。
  • 未用逗号引用,表格已完全展开并引用了结果。

最佳答案

在计算双反引号形式时,首先处理内部反引号,结果是单反引号形式。在评估内部反引号形式期间,仅评估前面有两个逗号的元素。但是,评估这些双未引用元素的结果仍然(单)未引用,因此在评估结果单反引号形式时再次评估。要仅以内部反引号形式实现评估,必须插入普通引号,从而生成 ,',

看看如何

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

评估为

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

关于macros - Common Lisp Double-Backquote, Unquote, Quote, Unquote 序列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17429521/

相关文章:

lisp - 如何衡量Lisp中方法的效率?

mysql - 来自 clsql-20110829 版本的 quicklisp 的 clsql-mysql 的 SBCL 加载错误

c++ - 如何驯服 Windows header (有用的定义)?

c - 使用#define 替换连续的字符串

c - 宏中的 GCC 变量类型

mysql - cl-dbi 从 sbcl 查询 mysql 时出现错误 - 非法 :UTF-8 character starting at position 18

scheme - 关于Scheme中的引号(')

character-encoding - 打开文件之前检测编码

lisp - Lisp "prog"在这个例子中是如何工作的?

scala - 将函数实现以编程方式将特定类型返回到另一个函数中