Consider the following MWE:
(setq a-cat 'derpy)
(let ((cats '(fluffy derpy)))
(while cats
(print cats)
(setq cats (delq a-cat cats))
(print cats)
(print (pop cats))))
The result looks like this:
(fluffy derpy) ; original local binding of "cats".
(fluffy) ; "cats" after the removal of 'derpy ("a-cat").
fluffy ; the first and only element left in "cats" (with pop).
nil ; empty "cats" after pop. the loop is over.
If i evaluate the expression several times the result is always the same. But if i wrap it inside a function definition something odd happens:
(setq a-cat 'derpy)
(defun cats-test ()
(interactive)
(let ((cats '(fluffy derpy)))
(while cats
(print cats)
(setq cats (delq a-cat cats))
(print cats)
(print (pop cats)))))
(cats-test)
First result (as expected):
(fluffy derpy)
(fluffy)
fluffy
nil
Second and subsequent results:
(fluffy) ; "cats" local binding with only 1 element!??
(fluffy) ; "a-cat" wasn't found.
fluffy ; (pop cats).
nil ; end of loop.
If i'm not mistaken, since "cats" isn't a global variable it's value should remain untouched after calling the function.
If i store the expression inside an anonymous function (with (lambda ())
) and call it (with funcall
), the result is the same as evaluating the expression alone, i.e. no weird list modification.
What exactly is going on here?
Edit:
This prevents the list from being modified after subsequent calls of the "cats-test" function:
(defun cats-test ()
(interactive)
(let ((cats (list 'fluffy 'derpy)))
(while cats
...
Now each time the function is called the original value of the "cats" local variable is (re)defined through the list
function.