推送不会将列表修改为函数参数
Push doesn't modify the list being a function argument
我是普通 lisp 的新手,所以希望有人能给我澄清一下:
假设我们有一个列表,想要添加一个带有 push
的项目来修改它:
CL-USER> (defparameter xx '(1 2 3))
XX
CL-USER> xx
(1 2 3)
CL-USER> (push 100 xx)
(100 1 2 3)
CL-USER> xx
(100 1 2 3)
符合预期。但是当我尝试对函数做同样的事情时,它不会修改列表:
CL-USER> (defun push-200 (my-list)
(push 200 my-list))
PUSH-200
CL-USER> (push-200 xx)
(200 100 1 2 3)
CL-USER> xx
(100 1 2 3)
所以我试着像这样比较参数和我的列表:
CL-USER> (defun push-200 (my-list)
(format t "~a" (eq my-list xx))
(push 200 my-list))
WARNING: redefining COMMON-LISP-USER::PUSH-200 in DEFUN
PUSH-200
CL-USER> (push-200 xx)
T
(200 100 1 2 3)
CL-USER> xx
(100 1 2 3)
它说对象是相同的。
所以问题是:我在这里忽略了什么?
(defun push-200 (my-list)
(push 200 my-list))
这会修改变量 my-list
。该变量现在指向一个新的 cons.
基本上是:(setq my-list (cons 200 my-list)
.
(push-200 xx)
Common Lisp 将 xx
计算为一个值并将列表传递给 push-200
。 xx
不是传递的,而是它的值。因此,Lisp 系统无法修改 xx
以指向不同的缺点,因为它未通过。
这(本质上)与以下突出显示的问题相同:
(let ((a (list 2 3 4 5)))
(let ((b a))
(push 1 a)
(list (eql a b)
(eql (cdr a) b))))
当运行.
时,此表格应return(NIL T)
Rainer Joswig 撰写的内容(以及 Vatine 演示的内容)。只需将 (push <A> <B>)
替换为 (setq <B> (cons <A> <B>))
,因为 push
is a macro:
"push item place => new-place-value"
并且,
"new-place-value [is] a list (the new value of place)"
注意 CLHS 没有说 "(更新的结构引用的地方)".
所以,地方的值改变了。在你的例子中,那个地方是局部变量 my-list
。在 (setq ...)
之前是 eq
到 xx
,但在它之后显然是 而不是 。要实际更改列表结构,您可以使用 rplaca
and ⁄ or rplacd
。
我们可以考虑在 Common Lisp 中传递参数,就像传递的是一个指向值的指针一样;指针本身通过 值 传递,即复制。所以 xx
"points" 在某个列表中;并且最初 my-list
"points" 在相同的内存位置。这就是初始 eq
测试成功的原因。
我是普通 lisp 的新手,所以希望有人能给我澄清一下:
假设我们有一个列表,想要添加一个带有 push
的项目来修改它:
CL-USER> (defparameter xx '(1 2 3))
XX
CL-USER> xx
(1 2 3)
CL-USER> (push 100 xx)
(100 1 2 3)
CL-USER> xx
(100 1 2 3)
符合预期。但是当我尝试对函数做同样的事情时,它不会修改列表:
CL-USER> (defun push-200 (my-list)
(push 200 my-list))
PUSH-200
CL-USER> (push-200 xx)
(200 100 1 2 3)
CL-USER> xx
(100 1 2 3)
所以我试着像这样比较参数和我的列表:
CL-USER> (defun push-200 (my-list)
(format t "~a" (eq my-list xx))
(push 200 my-list))
WARNING: redefining COMMON-LISP-USER::PUSH-200 in DEFUN
PUSH-200
CL-USER> (push-200 xx)
T
(200 100 1 2 3)
CL-USER> xx
(100 1 2 3)
它说对象是相同的。 所以问题是:我在这里忽略了什么?
(defun push-200 (my-list)
(push 200 my-list))
这会修改变量 my-list
。该变量现在指向一个新的 cons.
基本上是:(setq my-list (cons 200 my-list)
.
(push-200 xx)
Common Lisp 将 xx
计算为一个值并将列表传递给 push-200
。 xx
不是传递的,而是它的值。因此,Lisp 系统无法修改 xx
以指向不同的缺点,因为它未通过。
这(本质上)与以下突出显示的问题相同:
(let ((a (list 2 3 4 5)))
(let ((b a))
(push 1 a)
(list (eql a b)
(eql (cdr a) b))))
当运行.
时,此表格应return(NIL T)
Rainer Joswig 撰写的内容(以及 Vatine 演示的内容)。只需将 (push <A> <B>)
替换为 (setq <B> (cons <A> <B>))
,因为 push
is a macro:
"push item place => new-place-value"
并且,
"new-place-value [is] a list (the new value of place)"
注意 CLHS 没有说 "(更新的结构引用的地方)".
所以,地方的值改变了。在你的例子中,那个地方是局部变量 my-list
。在 (setq ...)
之前是 eq
到 xx
,但在它之后显然是 而不是 。要实际更改列表结构,您可以使用 rplaca
and ⁄ or rplacd
。
我们可以考虑在 Common Lisp 中传递参数,就像传递的是一个指向值的指针一样;指针本身通过 值 传递,即复制。所以 xx
"points" 在某个列表中;并且最初 my-list
"points" 在相同的内存位置。这就是初始 eq
测试成功的原因。