Lisp 将宏存储推入功能,但不将其移出功能

Lisp 将宏存储推入功能,但不将其移出功能,lisp,common-lisp,mutability,Lisp,Common Lisp,Mutability,我有一个功能: (defun multi-push (L P) (print (if L "T" "F")) (print P) (when L (multi-push (cdr L) (push (car L) P))) P) 我试图将一个列表推到另一个列表上(我知道输入列表L是反向的。这是出于设计)。print语句是有意义的,但是当我查看变量P时,它并没有像我预期的那样发生突变 示例REPL输出: CL-USER> bob (3 3 3) CL-USER>

我有一个功能:

(defun multi-push (L P)
  (print (if L "T" "F"))
  (print P)
  (when L
    (multi-push (cdr L) (push (car L) P)))
  P)
我试图将一个列表推到另一个列表上(我知道输入列表
L
是反向的。这是出于设计)。print语句是有意义的,但是当我查看变量
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
(根据[)将其第二个参数在适当的位置进行了变异。我还尝试了一些变体,在再次调用
L
P
上的
multi-PUSH
之前,我将
POP
P


需要注意的一点是,
(13)
行是
多推功能的输出。这也让我感到困惑。

推的破坏性变化是绑定,而不是列表。
推的更正确的修改是一个“位置”,它是

一种适合用作一般参考的形式

其中“广义参考”是

对存储对象的位置的引用,就像对变量的引用一样

这两段引用自CLHS术语表:讨论这一点的部分是

特别是:

> (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)) (b)(a) (f a b) (不是(等式a b)))

那是真的


您可以将
(push x y)
看作是扩展到类似
(setf y(cons x y))的内容
,只是它可以正确地处理多次求值。

更明确地说,PUSH是一个宏,它可以转换为代码来完成工作。它不是一个函数,不能作为函数编写。它看起来像是在试图跟踪函数在每次调用中接收到的输入。如果是这样,您可以去掉print语句和改为(跟踪多推)。调试完成后,执行(取消跟踪多推)@Xach:我现在已经澄清了:对不起,我应该在原始答案中这样说。您的
multipush
是一个函数,但请注意
push
是一个宏。这是有充分理由的。