函数n在应用于Common Lisp中的函数参数时访问哪个对象?

时间:2012-12-24 09:14:17

标签: lisp common-lisp

使用访问者功能 nth 时遇到问题。我将一个列表传递给某个函数并使用 nth 对函数列表中的元素进行新绑定,然后当我从函数中调用该列表时,它被修改,并且它不是我的想!会发生什么?

一些例子

(defun test (x) (incf x)) => TEST
(setq a 1) => 1
(test a) => 2
a => 1

我理解上面发生了什么,但是如果我们将所有内容更改为列表,那么就会发生一些我无法理解的事情

(defun test (x) (incf (nth 0 x))) => TEST
(setq a '(1)) => (1)
(test a) => 2
a => (2)

我期望a为(1),为什么它被修改了?我还尝试了其他功能,如 car first ,结果是一样的。

PS,我在Lispworks和SBCL中尝试过,结果相同。

3 个答案:

答案 0 :(得分:4)

(defun test (x) (incf x)) => TEST
(setq a 1) => 1
(test a) => 2
a => 1

您将1传递给test。在测试中,您修改了局部变量xa未更改且无法以此方式更改 - 我们传递a的值而不是a的引用。

(defun test (x) (incf (nth 0 x))) => TEST
(setq a '(1)) => (1)
(test a) => 2
a => (2)

您将列表(1)传递给测试。该列表未复制。局部变量x指向列表中的第一个cons单元格。然后,将第一个cons单元的 car 修改为2.由于未复制列表,因此修改传递的列表。 a也指向该列表的第一个cons单元格。所以它也是(2)

答案 1 :(得分:3)

如果您不想修改任何内容,请不要使用incf。使用1+。使用incf的唯一原因是因为你想要它的副作用。

至于为什么会发生这种情况,在传递给函数之前会对参数进行求值。当testa为1时调用a时,您传递的值为1,无法修改。当setf解析为列表时,如果您选择使用破坏性功能,则会传递一个列表,该列表可以在整个商店中{{1}}。

答案 2 :(得分:2)

请参阅nth上的文档。 nth会返回setq可以继续操作的地方。

  

nth可用于指定setf的位置。特别,   (setf(nth n list)new-object)==(setf(car(nthcdr n list))new-object)