Pascal Bourguignon <pjb@informatimago.com> wrote:
+---------------
| rpw3@rpw3.org (Rob Warnock) writes:
| > p.s. Note that by using a considerable amount of imperative mutation,
| > you *can* return the "same" LIST-type object with a new element
| > "inserted" into it IF the LIST-type object is a CONS ...
| > RPLACA the new contents into the original CONS and also
| > RPLACD the original CONS with the newly-alocated one:
|
| Yes. This other can of worm allows us to mention that in addition,
| there is a strong tradition of structure sharing in lisp (which is
| possible to do efficiently by the very fact that there is no list data
| type), and that applying destructive operations like this doesn't mesh
| well with that tradition.
+---------------
I completely agree -- it breaks the functional model completely --
and I was not *recommending* it per se, just pointing out that if one
really wanted to one *can* do it while maintaining object identity
with the first CONS.
Anyway, the bigger point was that one *CAN'T* do that if the initial
list arg is NIL, since NIL (considered as a value, not a symbol) is
immutable. So if one really wants a list-type "object" that one can
insert into anywhere and/or empty out completely while maintaining
object identity, it would really be better to create a wrapper object
for the object identity part of it, e.g.:
> (defstruct list-obj head)
LIST-OBJ
> (make-list-obj :head (list 3 2 1))
#S(LIST-OBJ :HEAD (3 2 1))
> (push 4 (list-obj-head *))
(4 3 2 1)
> **
#S(LIST-OBJ :HEAD (4 3 2 1))
>
This will maintain object identity even when "empty", which normal
CL lists won't:
> (eq (list) (list))
T
> (eq (make-list-obj :head nil) (make-list-obj :head nil))
NIL
>
Plus, it lets one add hooks for better performance if some of
the operations are more frequent than others, e.g., add a TAIL
slot, allowing appending to the end in O(1) time. And so forth...
-Rob
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607