- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我一直在尝试编写一个宏,除其他外,生成一个同名的编译器宏。这是我坚持使用的最少代码:
(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/
是否可以传递带有宏触发器的字符串作为宏参数?请参阅下面的示例代码: options mprint; %let string5='%abc%def%'; %macro test(string); dat
我意识到我的代码的某个部分由看起来相似的方法组组成(就像我有多个三重奏:一个辅助函数被另外两个为程序员准备的函数调用)。我正在尝试编写一个宏来为我定义这三个函数,这样我需要做的就是调用宏。但我的尝试导
这个问题在这里已经有了答案: What can you do with Lisp macros that you can't do with first-class functions? (8 个回答
在 haxe 宏中,对于每个表达式,我们可以以 http://api.haxe.org/haxe/macro/Position.html 的形式获取它的位置。 : { file:String,
如果我评价 (def ^:macro my-defn1 #'defn) 定义了一个名为“my-defn1”的宏,我可以像使用“defn”一样使用它。 但是,如果我改为求值 (if true (de
我想知道这段代码输出背后的原因。我想不出答案。 #define f(a,b) a##b #define g(a) #a #define h(a) g(a) void main() { print
我正在尝试编写一个宏,该宏扩展为具有解构的 let 形式。我的问题是我想拥有以 let 形式定义的符号列表,包括通过解构获得的符号列表。 用例 我试图排除这种行为,例如验证: (let [a (foo
这段代码: macro FL(message) return @sprintf("%s:%d | %s", @__FILE__, @__LINE__, message) # line 2 en
此宏的目的是创建一个宏,该宏为访问关联列表的某个键提供名称。 (defmacro generate-accessor (key-symbol prefix) (let ((mac-name
在mcpp.exe --help Options available with only -@std (default) option: -@compat Expand recursive ma
鉴于: (define-syntax (test stx) (syntax-case stx () [(_ body ...) (with-syntax ([body0 (pro
Doug Hoyte 在他对 Let Over Lambda 的介绍中将 symb 函数定义为使用宏进行元编程的基本实用程序: 在剪辑中: (defun mkstr (&rest args) (w
我的代码需要两种模式,debug 和 verbose。我在头文件中将它们定义为, #define verbose TRUE #define debug TRUE 到目前为止,在我的代码中,我一直在使用
Set-macro-character 有一个名为 non-terminating-p 的可选参数。好像是用来表示读完宏字符后是否要读另一个字符,但是reader algorithm似乎忽略了这个论点
我一直在搜索,但几乎找不到关于 LibreOffice Basic 的信息 我有点习惯在 excel 中编写宏,但这次需要做一个循环,直到我到达第一个空列并且它需要在 libreoffice 中。 在
我正在尝试编写一个调用某些函数的宏。这些函数只能由宏使用,因此我将它们放在包装宏的 letfn 中。伪代码: (letfn [(fn-a [] ...) (fn-b [] ...)
我发现对于任何在 clojure.tools.macro 中编写类似 defn 的宏的人来说,这将是一个很棒的工具。图书馆:name-with-attributes功能。文档字符串说: To be u
假设: (defmacro testing (&optional var) `(list 'this 'is ,@(when (consp var) `('a 'list)))
在 SBCL 中,我可以使用以下内容获取函数的文档字符串: (documentation #'mapcar t) 但是,我不明白如何获取宏的文档字符串。例如,给定宏: (defmacro with-l
想了解 undef 和将宏定义为 0 之间的区别。谢谢。 最佳答案 #define MACRO 0 定义预处理器标记 MACRO成为文字 0 #undef MACRO 删除预处理器标记 MACRO 的
我是一名优秀的程序员,十分优秀!