gpt4 book ai didi

macros - 生成包裹在 let 绑定(bind)变量中的宏形式的宏

转载 作者:太空宇宙 更新时间:2023-11-03 18:36:57 25 4
gpt4 key购买 nike

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

 (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 绑定(bind) ((a ,a) (b ,b))。我无法解决的问题是如何生成编译器宏形式,以便 lambda 绑定(bind)的内容在扩展中未被引用。我了解如何手动执行此操作,但我不确定如何对任意 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)))

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

(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 Comma ,“如果在反引号表达式的正文之外使用逗号,则逗号无效”。我认为这意味着您最好的选择是:

(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)))))

关于macros - 生成包裹在 let 绑定(bind)变量中的宏形式的宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21863997/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com