参数未按预期传递给lisp宏

时间:2018-10-17 05:12:18

标签: common-lisp gnu-common-lisp

我觉得自己和Basic Lisp Macro error在同一个球场 但是当我想象代码在扩展时的外观时,我看不到任何问题,宏扩展也无济于事,因为它只是不想输出我可以打印的任何内容; macroexpand只是为我运行代码。

(setf my-array (make-array 4 :initial-element 3))
(print my-array)

(setf (aref my-array 2) 5)
(print my-array)

(defmacro set3To5 (arrnum)
    (print (arrayp arrnum))
    (print arrnum)
    (setf (aref arrnum 3) 5)
)
(set3To5 my-array)

运行此命令会给我输出

argument MY-ARRAY is not an array

但是如果将'arrnum'替换为'my-array',那应该没问题吗?

引用链接的问题

  

现在,在进行宏扩展时,将使用参数VAR调用宏ADD-TEST来获取值G(一个符号)。

肯定是my-array是一个符号,它是我希望操纵的符号,所以为什么会出现问题?

2 个答案:

答案 0 :(得分:1)

让我们写下如果Lisp逐行评估您的文件会发生什么:

(setf my-array (make-array 4 :initial-element 3))

至此,我们已经将MY-ARRAY绑定到#(3 3 3 3)

(print my-array)

打印#(3 3 3 3)

(setf (aref my-array 2) 5)
(print my-array)

修改元素并打印#(3 3 5 3)

(defmacro set3To5 (arrnum)
  (print (arrayp arrnum))
  (print arrnum)
  (setf (aref arrnum 3) 5))

现在已经定义了宏SET3TO5

(set3To5 my-array)

这里的第一步(即使发生了,我们之前也没有提到)是宏扩展。编译器知道SET3TO5是一个宏,因此它将使用MY-ARRAY(符号)作为参数来调用宏函数。让我们看看该宏内部发生了什么:

(print (arrayp arrnum))

ARRNUM是符号MY-ARRAY,因此它会打印NIL,尽管可能不会出现在您期望的流中。

(print arrnum)

这将打印MY-ARRAY

(setf (aref arrnum 3) 5)

ARRNUM不是数组,因此您在这里出错。

因此我们无法评估此表达式,因为扩展宏失败。

您还可以执行其他一些操作:

(defun set1 (arrnum)
  (print (arrayp arrnum))
  (print arrnum)
  (setf (aref arrnum 3) 5))

(defun set2 (arrnum)
  (list 'setf (list 'aref arrnum 3) 5))

(defmacro set3 (arrnum)
  (list 'setf (list 'aref arrnum 3) 5))

现在评估:

CL-USER> (set1 my-array)
T
#(3 3 5 3)
5
CL-USER> my-array
#(3 3 5 5)
CL-USER> (set2 my-array)
(SETF (AREF #(3 3 5 5) 3) 5)
CL-USER> (set2 'foo)
(SETF (AREF FOO 3) 5)
CL-USER> (setf (aref my-array 3) 1)
1
CL-USER> (set3 my-array)
5
CL-USER> my-array
#(3 3 5 5)

答案 1 :(得分:-1)

长话短说,代码应如下所示,为您提供(3 3 5 5)数组。

(defmacro set3To5 (arrnum)
    `(print (type-of ,arrnum))
    `(setf (aref ,arrnum 3) 5)
)

至少,GNU Common Lisp非常关心`和'之间的区别(它们是反引号/反引号和引号/撇号字符)。 What does backtick mean in LISP? 逗号运算符取消对列表中元素的引号,允许您插入参数或局部变量,对列表中的内容进行“,@”拼接。

Lisp宏在其体内执行代码,返回结果应为可以执行的形式,即宏扩展。

似乎他们只是决定使用魔术来定义如何将两个反引号行都转换为代码,因为似乎您必须将它们都放在列表中并反引号整个列表,然后返回该列表,但是这样看起来确实更整洁。

相关问题