我的代码如下所示:
(defmacro createList (a b c)
(let ((lst (list a b c)))
(write lst)))
(createList 1 2 3 )
我明白了:
Illegal argument in functor position: 1 in (1 2 3).
我知道这里有一个类似的问题: Lisp Illegal argument in functor position
但我无法调整问题的答案。括号问题在哪里?我做错了什么?
答案 0 :(得分:4)
write
函数的结果是它的参数。因此,(write "Tom")
的结果是"Tom"
(它写入输出流的事实是函数的副作用)。
宏返回要评估的表单,通常表示列表。
您的宏创建列表(1 2 3)
,然后将其写出。在宏扩展时评估write
,而不是“运行时”。由于write
将其参数作为返回值返回,并且write
是最后调用的函数,因此宏函数的结果是write
函数的结果,或者,在这种情况下, (1 2 3)
。
(1 2 3)
,但是如果您尝试在顶层输入(1 2 3)
,它会看到1
作为表单的第一个参数,并尝试评估作为一个功能 - 它不是,它只是数字1。
如果您想查看宏将展开的内容,可以尝试:(macroexpand '(createlist 1 2 3))
您可以看到以下结果:
[2]> (macroexpand '(createlist 1 2 3))
(1 2 3)
(1 2 3) ;
T
您会看到第一个(1 2 3)
,这是您write
的结果。然后,您会看到第二个(1 2 3)
,它是宏扩展的结果(如上所述),后面是T
,这是macroexpand
函数的结果。
这就是发生了什么。不清楚如何解决它,因为它不清楚你想做什么。
也许这更像是你要做的事情:
(defmacro createlist (a b c)
`(list ,a ,b ,c))
[5]> (macroexpand `(createlist 1 2 3))
(LIST 1 2 3) ;
T
答案 1 :(得分:2)
write
返回传递给它的对象,因为它是第一个参数。因此,您将从宏返回lst
。无论您从宏返回什么,都被视为lisp代码。
运行代码时,您应该看到
(1 2 3)
在错误之前的标准输出上。这就是您给write
的内容:(list a b c)
a
绑定到1
等的结果。
lisp代码中列表的第一个元素是被调用的函数。显然,1
,这是该列表的第一个元素,不是一个函数。
为了调试此类错误,使用macroexpand
通常很有用:
(defmacro createList (a b c)
(let ((lst (list a b c)))
(write lst)))
(format t "~%Expanded ~a~%" (macroexpand-1 '(createList 1 2 3)))