以编程方式引用(即,对于宏)

时间:2013-01-31 08:39:00

标签: common-lisp macrodef

我希望能够做到这一点:

(mapcar #'quote '(1 2 3 4))

得到这个

  

('1'2'3'4)

但是,由于QUOTE是一种特殊形式,因此无法进行操作。

我试图把它搞砸了:

(defmacro quoter (&rest args)
  `(loop for arg in ,@args collect (quote arg)))

(quoter '(1 2 3 4 ))

但是,正如我所料,这会让我感到高兴....

(LOOP FOR ARG IN '(1 2 3 4)
      COLLECT 'ARG)

将输入转换为字符串然后转换为符号将不起作用 - 我可能有传入的形式,而不仅仅是原子。

我确定我在这里遗漏了一些东西。 : - )

3 个答案:

答案 0 :(得分:4)

这将产生您想要的扩展:

(defmacro quoter (&rest args)
   (loop for arg in args collect `(quote ,arg)))

...但是这样的宏不太可能是你想要的更高级别(除非你只想玩宏)。扩展不是有效的列表形式,因此使用它的唯一方法是自己调用MACROEXPAND。如果你要打电话给MACROEXPAND,为什么不把它变成一个函数并调用那个函数呢?

答案 1 :(得分:3)

如果您想将项目转换为(quote item)格式,则必须提供转换。

例如(list 'quote item)

`(quote ,item)

如果在函数中使用特殊形式或宏,则可以使用该函数并将其传递给MAPCAR

CL-USER > (mapcar #'(lambda (item) (list 'quote item)) '(1 2 3 4))

((QUOTE 1) (QUOTE 2) (QUOTE 3) (QUOTE 4))

如果列表被变量替换,这也适用。

如果你想把它写成宏,那么你得到的问题是你获得了源代码,你需要对其进行转换。如果您有一个列表,那么您可以直接转换它。如果你有一个变量,那么你就不能(因为你不知道这个变量的值),你可以将变换包含在生成的源中。

示例:

CL-USER 119 > (defmacro quoter (list)
                (list 'quote (mapcar (lambda (item) (list 'quote item))
                                     (second list))))
QUOTER

CL-USER 120 > (macroexpand '(quoter '(1 2 3 4)))
(QUOTE ((QUOTE 1) (QUOTE 2) (QUOTE 3) (QUOTE 4)))
T

CL-USER 121 > (quoter '(1 2 3 4))
((QUOTE 1) (QUOTE 2) (QUOTE 3) (QUOTE 4))

但现在它不知道如何处理(quoter some-variable)。现在你无法转换列表 - 因为它不知道。现在你需要提供一个宏扩展,它将在运行时进行转换......

答案 2 :(得分:2)

这样的单线是:

(mapcar (lambda (x) `',x) '(1 2 3 4))

请注意引号的用法。我觉得这个形式有时很有用。

相关问题