For example, I have function stack-push
which pushes element onto the stack.
(defun stack-push (stack element)
(if (not (listp element))
(setf stack (cons element stack))
(dolist (current-el (reverse element))
(setf stack (cons current-el stack)))))
But when I invoke it like (stack-push *some-stack* '(a b c d e))
, it doesn't affect on *some-stack*
. Could you explain why?
setf
with a symbol as place like (setf stack (cons element stack))
expands to (setq stack (cons element stack))
. This usually happens when you create your function. Your function becomes this:
(defun stack-push (stack element)
(if (not (listp element)
(setq stack (cons element stack))
(dolist (current-el (reverse element))
(setq stack (cons current-el stack)))))
Note that I have only expanded setf
here. Both defun
and dolist
becomes quite horrendous expansions that makes the code more unreadable. The system expands the forms fully so the code that runs has no macros.
setq
updates a binding so when it updates stack
that is what it updates, not *some-stack*
. Here is exactly what is happening if you do (stack-push *some-stack* "a")
:
*some-stack*
and "a"
. It evaluates its arguments. *some-stack*
evaluates to address A that has a cons
cell eg. ("b")
."a"
is a literal residing at address Bstack
points to A and element points to B. element
points to B (not (listp element)) ; ==> t
and the code follows the consequent.(setf stack (cons element stack))
was before runtime changed to (setq stack (cons element stack))
. (cons element stack)
calls cons
with B and A as arguments. returns a new cell with address C ("a" "b")
setq
updates so that binding stack
points to C. stack-push
returns the last evaluated value, which is the result of the setq
which is the second argument C. In the function there is no mention of *some-stack*
. The binding is never references or updated. Only stack
is updates with what new value to point to.
As a consequence of this being a function you can call your function with literals, which normally would not work if the argument was a variable meant to be updated.
(stack-push '("b") "a") ; ==> ("a" "b")
There is a form called push
. It is not a function. You can see what it does:
(macroexpand '(push "a" *some-stack*))
; ==> (setq *some-stack* (cons "a" *some-stack*))
Thus for push
to work you need that second argument is something setf
-able. Trying it with literals expands to unrunnable code. For types you can make your own setf
expander such that setf
and push
works.