In no case does remove
modify the original object or any of its elements.
remove
will traverse the object looking for elements which match thing to be removed
- if are no such elements it may return either a copy of the original object with same type or the original object;
- if are such elements it will return a new object which has those elements removed but which is same type as original object..
In second case the returned object may share structure with original object. This really applies only for lists.
Example for lists, it is allowed that
(let ((x (list 1 2 3)))
(eq (remove 1 x) (cdr x)))
may return true. Is actually unlikely it will do so, because implementation of remove
which can do this check would be quite hard to see how it would be better, but is allowed to be the case.
Here is implementation of simple version of remove
which works only on lists and which does not ever share:
(defun remove-from-list (e l)
(loop for thing in l
when (eql thing e) collect thing))
Here is version which does share, you can see why this is nasty.
(defun remove-from-list (e l)
(labels
((rfll (lt et)
(cond
((null lt) ;done with list
'())
((null et) ;done with es
lt)
((eq lt et) ;hit first e
(rfll (rest lt) (member e (rest lt))))
(t ;are es but not yet
(cons (first lt) (rfll (rest lt) et))))))
(rfll l (member e l))))
Perhaps there are better approaches than this one: certainly there are which can be made tail recursive or iterative, but need to keep looking to know when to copy is expense.