将列表传递给Common Lisp中的宏

时间:2019-06-20 19:43:53

标签: macros lisp common-lisp metaprogramming quote

在将列表传递给宏时遇到问题,该列表将用于生成函数名称。例如,下面的代码将导致错误。

(defmacro gen (str-lst)
  `(defun ,(intern (string-upcase (car str-lst))) () (print "foo")))

(gen '("foo" "bar"))

产生的错误是:

  

***-DEFUN / DEFMACRO:QUOTE是一种特殊的运算符,不能重新定义。可以使用以下重新启动:ABORT:R1
  中止主循环

我应该如何修改我的代码,我的代码有什么问题?

让我更加困惑的是,下面的代码(答案退出here)可以正常工作。

(defmacro easy-one (str-lst)
  `(mapc #'(lambda (str) (print str)) ,str-lst))
(easy-one '("foo" "bar"))

1 个答案:

答案 0 :(得分:7)

不引用列表。宏不评估其参数,因此您不需要像对普通函数那样对它们进行引用以防止对它们进行评估。

(gen ("foo" "bar"))

引用时表示您正在执行

(get (quote ("foo" "bar")))

str-list的值是列表(quote ("foo" "bar")),因此(car str-list)是符号QUOTE。结果,宏扩展为

(defun quote () (print "foo"))

这就是为什么您在尝试重新定义内置QUOTE时收到错误消息的原因。

第二个示例的区别在于,您只是将参数替换为扩展,而不是在扩展代码中使用其值。因此扩展为

(mapc #'(lambda (str) (print str)) '("foo" "bar")))

在此列表将在扩展运行时使用,而不是在宏扩展时使用。需要在其中将其引号,以防止将其作为函数调用进行评估。

您应使用macroexpand来查看调试时宏的扩展方式。