繁体   English   中英

生成宏形式的宏包含在绑定变量中

[英]Macro that generates macro form wrapped in let bound variables

我一直在尝试编写一个宏,除其他外,生成一个同名的编译器宏。 这是我坚持的最小代码:

 (defmacro definline (name lambda-list &body body)
  `(define-compiler-macro ,name ,lambda-list
     `(let ,,(mapcar (lambda (v) ``(,',v ,,v)) lambda-list)
        ,,@body)))

我想要的是这样的:

(definline foobar (a b) (print "foobar") (+ a b))
;; Expands to
(define-compiler-macro foobar (a b)
  `(let ((a ,a) (b ,b))
     (print "foobar") (+ a b)))

但我无法弄清楚如何生成let绑定((a ,a) (b ,b)) 我无法解决的问题是如何生成编译器宏表单,以便在扩展中不引用 lambda绑定的内容。 我理解如何手动执行此操作,但我不确定如何对任意lambda列表执行此操作。

编辑:

经过一些更多的摆弄,我想出了这个。 哪个有效。 但是,它很可怕。

(defmacro definline (name lambda-list &body body)
  (read-from-string
   (format nil "(define-compiler-macro ~S (~{~S~^ ~})
                    `(let (~{(~S ,~S)~})
                       ~{~S~}))"
           name lambda-list (loop for l in lambda-list nconc (list l l)) body)))

如果修改了一些与I / O相关的变量,那么使用format的方法根本不起作用。 使用format生成符号名称通常非常脆弱且不可移植。 一个难以解决的问题,并且可能更容易使用列表构造而不是单独的反引号来处理它。 例如,在这种情况下,我们可以:

(defmacro definline (name variables &body body)
  (list 'define-compiler-macro name variables
        `(list* 'let (list ,@(mapcar (lambda (variable)
                                       `(list (quote ,variable) ,variable))
                              variables))
                ',body)))

这样做:

CL-USER> (pprint (macroexpand-1 '(definline foobar (a b) 
                         (print "foobar")
                         (+ a b))))

(DEFINE-COMPILER-MACRO FOOBAR
    (A B)
  (LIST* 'LET (LIST (LIST 'A A) (LIST 'B B)) '((PRINT "foobar") (+ A B))))

除非我误读某些内容,否则应该具有与以下相同的结果:

(define-compiler-macro foobar (a b)
  `(let ((a ,a) (b ,b))
     (print "foobar")
     (+ a b)))

我不认为单独使用反引号生成后一种形式是不可能的。 问题在于,由于规范没有确切地定义反引用是如何实现的,因此它并不像那样简单

(define-compiler-macro foobar (a b)
  (backquote (let ((a (unquote a))
                   (b (unquote b)))
               (print "foobar")
               (+ a b)))

如果您的实现确实以这种方式实现它,那么您可以编写一个生成该类型输出的扩展。 除非你从实现中获得这样的保证,否则我认为没有办法获得你需要注入更高层的“逗号变量”。 很难清楚地说明这一点,但你可能会看到这个尝试:

(defmacro definline (name variables &body body)
  `(define-compiler-macro ,name ,variables
     `(let ,',(mapcar (lambda (variable)
                        `(,variable (unquote ,variable)))
                      variables)
        ,@',body)))

这将产生如下结果:

(DEFINE-COMPILER-MACRO FOOBAR
    (A B)
  '(LET ((A (UNQUOTE A)) (B (UNQUOTE B)))
     (PRINT "foobar")
     (+ A B)))

请注意,SBCL已经足够聪明,可以用正常引号替换反引号,因为内部没有任何内容需要取消引用。 生成拼接形式的mapcar无法生成带逗号的代码,因为没有指定这些逗号是如何实现的,并且根据2.4.7逗号 ,“如果在主体内部使用逗号 ,则逗号无效反引号表达式“。 我认为这意味着你最好的选择是这样的:

(defmacro definline (name variables &body body)
  `(define-compiler-macro ,name ,variables
     `(let ,(mapcar 'list 
                    ',variables
                    (list ,@variables))
        ,@',body)))

在不同的实现中,这种扩展会有所不同,但在SBCL中它是:

(DEFINE-COMPILER-MACRO FOOBAR (A B)
  `(LET (SB-IMPL::BACKQ-COMMA (MAPCAR 'LIST '(A B) (LIST A B)))
     (PRINT "foobar")
     (+ A B)))

在CCL中你会得到:

(DEFINE-COMPILER-MACRO FOOBAR (A B)
  (LIST* 'LET
         (LIST* (MAPCAR 'LIST '(A B) (LIST A B))
                '((PRINT "foobar") (+ A B)))))

在CLISP中:

(DEFINE-COMPILER-MACRO FOOBAR (A B)
 (CONS 'LET
  (CONS (MAPCAR 'LIST '(A B) (LIST A B)) '((PRINT "foobar") (+ A B)))))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM