1

我觉得好像我与Basic Lisp Macro 错误处于同一个球场, 但是当我想象代码在展开时应该是什么样子时,我没有看到问题并且 macroexpand 没有帮助,因为它只是不想输出任何东西我可以打印;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' 取代,那应该没问题吧?

引用链接的问题

现在在宏扩展上,调用宏 ADD-TEST 并使用参数 VAR 获取值 G,一个符号。

当然 my-array 是一个符号,它是我想要操作的符号,那么为什么会有问题呢?

4

2 回答 2

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

Well ARRNUMis the symbol MY-ARRAYso this prints NIL,尽管可能不是您期望的流。

(print arrnum)

这打印MY-ARRAY

(setf (aref arrnum 3) 5)

WellARRNUM不是数组,所以这里有错误。

所以我们未能评估这个表达式,因为扩展宏失败了。

以下是您可以做的其他一些事情:

(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)
于 2018-10-17T19:06:46.020 回答
-1

长话短说,代码应该看起来像这样,为您留下一个 (3 3 5 5) 的数组。

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

至少,GNU Common Lisp 非常关心 ` 和 ' 之间的区别(那些是反引号/反引号和引号/撇号字符)。 LISP 中的反引号是什么意思? 逗号操作符取消对列表中元素的引用,允许您插入参数或局部变量,使用“,@”拼接列表。

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

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

于 2018-10-17T05:56:27.413 回答