我有一个函数:
(defun multi-push (L P)
(print (if L "T" "F"))
(print P)
(when L
(multi-push (cdr L) (push (car L) P)))
P)
我试图将一个列表推送到另一个列表(我知道输入列表L
是相反的。这是设计使然(。打印语句是有意义的,但是当我查看变量P
时,它并没有像我预期的那样发生突变。
示例 REPL 输出:
CL-USER> bob
(3 3 3)
CL-USER> (multi-push (list 1 2) bob)
"T"
(3 3 3)
"T"
(1 3 3 3)
"F"
(2 1 3 3 3)
(1 3 3 3)
CL-USER> bob
(3 3 3)
我做错了什么?我认为PUSH
(根据[http://clhs.lisp.se/Body/m_push.htm](改变了它的第二个论点。我还尝试过POP
L
并将其PUSH
到P
上的变化,然后再L
和P
调用multi-push
。
需要注意的一点是,(1 3 3 3)
行是multi-push
函数的输出。这也让我感到困惑。
push
破坏性地变异的是绑定,而不是列表。 更准确地说,push
修改的是一个"地方",它是
适合用作广义参考的表格
其中"广义引用"是
对存储对象的位置的引用,就像对变量一样。
这两句话来自CLHS词汇表:讨论这个问题的部分是5.1。
特别:
> (let* ((l1 '(1 2 3))
(l2 l1))
(push 0 l1)
(values l1 l2))
(0 1 2 3)
(1 2 3)
还要注意,这是合法的CL,因为它不会破坏性地改变引用的列表结构。push
必须是一个宏,因为函数不能做它所做的事情:你不能编写一个函数f
这样:
(让* ((A (列表 1 2 3(( (二(( (fa b( (不是(等式 b(((
会是真的。
你可以把(push x y)
想象成扩展到类似(setf y (cons x y))
的东西,除了它会正确地处理多重求值。