Push doesn't modify the list being a function argument

无人久伴 提交于 2019-12-02 01:21:53
(defun push-200 (my-list)
  (push 200 my-list))

This modifies the variable my-list. The variable now points to a new cons.

It is basically: (setq my-list (cons 200 my-list).

(push-200 xx)

Common Lisp evaluates xx to a value and passes the list to push-200. xx is not passed, but the value of it. So, the Lisp system can't modify xx to point to a different cons, since it is not passed.

This is (essentially) the same problem highlighted by the following:

(let ((a (list 2 3 4 5)))
  (let ((b a))
    (push 1 a)
    (list (eql a b)
          (eql (cdr a) b))))

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, because push is a macro:

"push item place => new-place-value"

And,

"new-place-value [is] a list (the new value of place)"

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 was eq to xx before the (setq ...), but obviously not, after it. To actually alter a list structure you can use rplaca and ⁄ or rplacd.

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 initially my-list "points" at the same memory location. That's why the initial eq test succeeds.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!