将列表传递给 Common Lisp 中的宏
pass a list to macro in Common Lisp
我在将列表传递给宏时遇到问题,该列表将用于生成函数名称。例如,下面的代码会导致错误。
(defmacro gen (str-lst)
`(defun ,(intern (string-upcase (car str-lst))) () (print "foo")))
(gen '("foo" "bar"))
产生的错误是:
*** - DEFUN/DEFMACRO: QUOTE is a special operator and may not be redefined. The following restarts are available: ABORT :R1
Abort main loop
我应该如何修改我的代码,我的代码有什么问题?
让我更加困惑的是下面的代码,关于哪个答案存在here,工作正常。
(defmacro easy-one (str-lst)
`(mapc #'(lambda (str) (print str)) ,str-lst))
(easy-one '("foo" "bar"))
不要引用列表。宏不会计算它们的参数,因此您不需要引用它们来防止它们被计算,就像您对普通函数所做的那样。
(gen ("foo" "bar"))
当你引用它时,你正在执行
(get (quote ("foo" "bar")))
str-list
的值是列表(quote ("foo" "bar"))
,所以(car str-list)
是符号QUOTE
。结果,宏扩展为
(defun quote () (print "foo"))
这就是为什么您会收到一条错误消息,抱怨您正在尝试重新定义 built-in QUOTE
。
第二个示例的不同之处在于,您只是将参数替换到扩展中,而不是在扩展代码中使用它的值。所以它扩展为
(mapc #'(lambda (str) (print str)) '("foo" "bar")))
此处将在展开运行时使用列表,而不是在展开宏时使用。它需要在那里被引用,以防止它被评估为函数调用。
您应该使用 macroexpand
来查看您的宏在调试时是如何展开的。
我在将列表传递给宏时遇到问题,该列表将用于生成函数名称。例如,下面的代码会导致错误。
(defmacro gen (str-lst)
`(defun ,(intern (string-upcase (car str-lst))) () (print "foo")))
(gen '("foo" "bar"))
产生的错误是:
*** - DEFUN/DEFMACRO: QUOTE is a special operator and may not be redefined. The following restarts are available: ABORT :R1
Abort main loop
我应该如何修改我的代码,我的代码有什么问题?
让我更加困惑的是下面的代码,关于哪个答案存在here,工作正常。
(defmacro easy-one (str-lst)
`(mapc #'(lambda (str) (print str)) ,str-lst))
(easy-one '("foo" "bar"))
不要引用列表。宏不会计算它们的参数,因此您不需要引用它们来防止它们被计算,就像您对普通函数所做的那样。
(gen ("foo" "bar"))
当你引用它时,你正在执行
(get (quote ("foo" "bar")))
str-list
的值是列表(quote ("foo" "bar"))
,所以(car str-list)
是符号QUOTE
。结果,宏扩展为
(defun quote () (print "foo"))
这就是为什么您会收到一条错误消息,抱怨您正在尝试重新定义 built-in QUOTE
。
第二个示例的不同之处在于,您只是将参数替换到扩展中,而不是在扩展代码中使用它的值。所以它扩展为
(mapc #'(lambda (str) (print str)) '("foo" "bar")))
此处将在展开运行时使用列表,而不是在展开宏时使用。它需要在那里被引用,以防止它被评估为函数调用。
您应该使用 macroexpand
来查看您的宏在调试时是如何展开的。