0

I have a function:

(defun multi-push (L P)
  (print (if L "T" "F"))
  (print P)
  (when L
    (multi-push (cdr L) (push (car L) P)))
  P)

which I have made in an to attempt to push a list onto another list (I am aware the input list L is reversed. This is by design). The print statements make sense, but when I look at the variable P, it is not mutated as I expect.

Sample REPL output:

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)

What have I done wrong? I thought PUSH (according to [http://clhs.lisp.se/Body/m_push.htm]) mutates its second argument in place. I have also tried variations where I POP L and PUSH it onto P before calling multi-push on L and P again.

one thing of note is that the line (1 3 3 3) is the output of the function of multi-push. This also confuses me.

jellies
  • 639
  • 1
  • 5
  • 17
  • Your `multipush` is a function, but note that `push` is a macro. That is for a good reason. – Kaz Jan 06 '20 at 04:14

1 Answers1

1

What push mutates destructively is a binding, not a list. More correctly what push modifies is a 'place' which is

a form which is suitable for use as a generalized reference

where a 'generalized reference' is

a reference to a location storing an object as if to a variable.

These two quotes are from the CLHS glossary: the section which talks about this is 5.1.

In particular:

> (let* ((l1 '(1 2 3))
         (l2 l1))
    (push 0 l1)
    (values l1 l2))
(0 1 2 3)
(1 2 3)

And also note that this is legal CL since it doesn't destructively alter the quoted list structure. push must be a macro since a function can't do what it does: you can't write a function f such that:

(let* ((a (list 1 2 3)) (b a)) (f a b) (not (eq a b)))

would be true.

You can think of (push x y) as expanding to something like (setf y (cons x y)), except that it will deal with multiple-evaluation properly.

  • 2
    To be more explicit, PUSH is a macro that turns into code to do the work. It's not a function and could not be written as a function. – Xach Jan 05 '20 at 23:55
  • It looks as though you are trying to trace the inputs received by the function in each call. If so, you can get rid of the print statements and do instead (trace multi-push). When you are finished debugging, do (untrace multi-push) – Leo Jan 06 '20 at 02:55
  • @Xach: I've clarified that now: sorry I should have said that in the original answer. –  Jan 06 '20 at 10:37