I'm new to common lisp, so hope someone would clarify this to me:
say we have a list and want to add an item with push
to modify it:
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)
as expected. But when i try to do the same with the function, it doesn't modify a list:
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)
so i tried to compare argument and my list like this:
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)
it says the objects are identical. So the question is: what was the thing I've overlooked here?
This is (essentially) the same problem highlighted by the following:
This form should return
(NIL T)
when run.What Rainer Joswig writes (and Vatine demonstrates). Just replace
(push <A> <B>)
with(setq <B> (cons <A> <B>))
wherever you see it, becausepush
is a macro:And,
Notice CLHS didn't say "(the updated structure referred to by place)".
So, the value of place changes. And that place, in your case, is the local variable
my-list
. It waseq
toxx
before the(setq ...)
, but obviously not, after it. To actually alter a list structure you can userplaca
and ⁄ orrplacd
.We can think about argument passing in Common Lisp mostly as if what was passed is a pointer to a value; the pointer itself is passed by value, i.e. copied. So
xx
"points" at some list; and initiallymy-list
"points" at the same memory location. That's why the initialeq
test succeeds.This modifies the variable
my-list
. The variable now points to a new cons.It is basically:
(setq my-list (cons 200 my-list)
.Common Lisp evaluates
xx
to a value and passes the list topush-200
.xx
is not passed, but the value of it. So, the Lisp system can't modifyxx
to point to a different cons, since it is not passed.