LISP:函子位置的非法论证

时间:2016-03-02 23:31:28

标签: list macros lisp common-lisp

我的代码如下所示:

(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

但我无法调整问题的答案。括号问题在哪里?我做错了什么?

2 个答案:

答案 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)))

(Live)