(setf list (loop for i from 1 to 12 collect i))
(defun removef (item seq)
(setf seq (remove item seq)))
CL-USER> (removef 2 list)
(1 3 4 5 6 7 8 9 10 11 12)
CL-USER> (removef 3 list)
(1 2 4 5 6 7 8 9 10 11 12)
Why doesn't removef
really modify the variable?
In Common Lisp, parameters are passed "by identity" (this term goes back to D. Rettig, one of the developers of the Allegro Common Lisp implementation). Think of pointers (to heap objects) being passed by values, which is true for most Lisp objects (like strings, vectors, and, of course, lists; things are slightly more complicated, since implementations might also have immediate values, but that's beside the point here).
The
setf
ofseq
modifies the (private, lexical) variable binding of the function. This change is not visible outside ofremovef
.In order for
removef
to be able to affect the surrounding environment at the point of the call, you need to make it a macro:You might want to take at look at
setf
and the concept of generalized references. Note, that the macro version ofremovef
I provided above is not how it should actually be done! For details, read aboutget-setf-expansion
and its ugly details.If all you want to do is to destructively modify the list, consider using
delete
instead of remove, but be aware, that this might have unintended consequences:is not allowed by the ANSI standard (you are destructively modifying a literal object, i.e., part of your code). In this example, the mistake is easy to spot, but if you are 7 frames deep in some callstack, processing values whose origin is not entirely clear to you, this becomes a real problem. And anyway, even
might be surprising at first, even though
seems to "work". Essentially, the first example does not work as intended, as the function
delete
has the same problem as your original version ofremovef
, namely, it cannot change the caller's notion of thelist
variable, so even for the destructive version, the right way to do it is:Here is an example of an implementation of
removef
that is "able to affect the surrounding environment at the point of the call", as stated by @Dirk.The utilities length= , make-gensym-list and once-only are available at Project Alexandria.
BTW exists at Alexandria a removef definition that uses define-modify-macro but requires an auxiliary definition. This version does not requires an auxiliary defintion.