用嵌套的quasiquoting编写一个Lisp宏

时间:2012-03-22 03:55:55

标签: macros lisp

我试图写一个编写一堆宏的Lisp宏,但是我在生成使用splice运算符(在build-bind中)的宏代码时遇到了问题,它首先扩展了表达式。< / p>

(defmacro define-term-construct (name filter-p list-keywords)
  (let* ((do-list-name (output-symbol "do-~a-list" name))
         (with-name (output-symbol "with-~a" name))
         (do-filter-name (output-symbol "do-~as" name)))
   `(progn
       (defmacro ,do-list-name 
         (ls (&key ,@(append list-keywords '(id operation))) &body body)
          (with-gensyms (el)
           `(loop-list (,el ,ls :id ,id :operation ,operation)
              (let (XXX,@(build-bind ,,name ,el))
                 (when (,',filter-p ,el)
                    (,',with-name ,el
                          ,@body)))))))))

第一遍后,我想得到:

(define-term-construct some some-p (args name))

->

(PROGN
  (DEFMACRO DO-SOME-LIST (LS (&KEY ARGS NAME ID OPERATION) &BODY BODY)
   (WITH-GENSYMS (EL)
     `(LOOP-LIST (,EL ,LS :ID ,ID :OPERATION ,OPERATION)
        (LET (,@(BUILD-BIND ,SOME ,EL))
         (WHEN (SOME-P ,EL)
           (WITH-SOME ,EL
              ,@BODY)))))))

知道我应该使用什么引用/ quasiquotes来获得所需的代码?

1 个答案:

答案 0 :(得分:1)

您说想要获得的输出具有不平衡的逗号。 ,@已经平衡了反引号,因此您无法拥有,SOME,EL。这是两个级别的不引用/拼接内部只有一个反引用级别。

我怀疑你想要:

`(WITH-GENSYMS (EL) ... (LET (,@(BUILD-BIND 'SOME EL)) ...))

some符号作为原始宏的参数出现,并且在传递给build-bind函数时必须以引号结尾。 EL是直接评估的。它只是由WITH-GENSYMS绑定构造引入的局部变量,并且它不再处于反引号上下文中,因为它位于拼接内部。

将其转录回原始外部宏的反引号:SOME变为,name

,@(build-bind ',name el)  ;; two commas out balance two backquotes in

符号是保护引号下的拼接版,它将确保它被视为符号而不是变量。

el不需要拼接;它不是可变材料,而是生成模板的硬编码功能。如果您要放置,el,它会在el宏的范围内查找define-term-construct变量,其中不存在此类内容。