ore*_*uro 2 lisp macros metaprogramming common-lisp quote
我在将列表传递到宏时遇到问题,该列表将用于生成函数名称。例如,下面的代码将导致错误。
(defmacro gen (str-lst)
`(defun ,(intern (string-upcase (car str-lst))) () (print "foo")))
(gen '("foo" "bar"))
Run Code Online (Sandbox Code Playgroud)
产生的错误是:
***-DEFUN / DEFMACRO:QUOTE是一种特殊的运算符,不能重新定义。可以使用以下重新启动:ABORT:R1
中止主循环
我应该如何修改我的代码,我的代码有什么问题?
令我更加困惑的是,下面的代码(有关答案在此处退出)的运行正常。
(defmacro easy-one (str-lst)
`(mapc #'(lambda (str) (print str)) ,str-lst))
(easy-one '("foo" "bar"))
Run Code Online (Sandbox Code Playgroud)
不要引用列表。宏不评估其参数,因此您不需要像对普通函数那样引用它们以防止对其进行评估。
(gen ("foo" "bar"))
Run Code Online (Sandbox Code Playgroud)
当您引用它时,您正在执行
(get (quote ("foo" "bar")))
Run Code Online (Sandbox Code Playgroud)
的值str-list
是列表(quote ("foo" "bar"))
,(car str-list)
符号也是QUOTE
。结果,宏扩展为
(defun quote () (print "foo"))
Run Code Online (Sandbox Code Playgroud)
这就是为什么您在尝试重新定义内置命令时会收到错误消息QUOTE
。
第二个示例的区别在于,您只是将参数替换为扩展,而不是在扩展代码中使用其值。因此它扩展为
(mapc #'(lambda (str) (print str)) '("foo" "bar")))
Run Code Online (Sandbox Code Playgroud)
在此列表将在扩展运行时使用,而不是在宏扩展时使用。需要在其中将其引号,以防止将其作为函数调用进行评估。
您应该使用它macroexpand
来查看调试时宏的扩展方式。