我希望能够做到这一点:
(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)
将输入转换为字符串,然后转换为符号是行不通的 - 我可能有传入的形式,而不仅仅是原子。
我确定我在这里错过了一些东西。
这将产生您想要的扩展:
(defmacro quoter (&rest args)
(loop for arg in args collect `(quote ,arg)))
。但是这样的宏不太可能真的是你想要的更高层次(除非你只想玩宏)。扩展不是有效的列表表单,因此使用它的唯一方法是自己调用MACROEXPAND
。如果你要调用MACROEXPAND
,为什么不把它变成一个函数并调用那个函数呢?
如果要将项目转换为表单(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)
.现在您无法转换列表 - 因为它是未知的。现在,您需要提供一个宏扩展,以便在运行时进行转换...
这样做的单行是:
(mapcar (lambda (x) `',x) '(1 2 3 4))
请注意引号的用法。我发现这个表格有时很有用。