[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Writing Destructive Functions



" You can use SETF on the various list component accessors to alter the
contents of a list.

(defun replace-first (list new-element)
  (setf (car list) new-element)
  list)"

The problem that I'm having is not doing a subsitution for the first
element, but destructively adding elements to the head of a list.  An
example is

(defun add-to-front (theList new-element)
   ; do something magical)

then if you call it with

> (setf test-list '(a b c))
(A B C)
> (add-to-front test-list 'k)
(K A B C)

> test-list
(K A B C)

Unfortunately this does not seem to be possible, since we cannot truely
pass a pointer to "test-list", but only what "test-list" points to.

+-----------+
| test-list | 
+-----------+
     |
     v
+-----------+    +-----------+    +-----------+    
|     |     | -> |     |     | -> |     |     | -> nil
+-----------+    +-----------+    +-----------+    
   |                |                |             
   v                v                v             
   A                B                C             

What we get passed to our function is a new pointer to the 1st cons cells.

+-----------+
|   list    | 
+-----------+
     |
     v
+-----------+    +-----------+    +-----------+    
|     |     | -> |     |     | -> |     |     | -> nil
+-----------+    +-----------+    +-----------+    
   |                |                |             
   v                v                v             
   A                B                C             


We can change the values of this cons cell to our hearts content with
things like:

 (setf (car list) 'new-element)

or

 (setf list (cons new-element list))

etc, but when we return "test-list" still points to this first cons cell. 
What we want is to change the cons cell that "test-list" points to, i.e.
after the funtion returns, test-list now points to:


+-----------+
| test-list | 
+-----------+
     |
     v            old 1st cons
+-----------+    +-----------+    +-----------+    +-----------+    
|     |     | -> |     |     | -> |     |     | -> |     |     | -> nil
+-----------+    +-----------+    +-----------+    +-----------+    
   |                |                |                |             
   v                v                v                v             
   K                A                B                C             


So far the only answer that I have come up with is a macro:

> (defmacro replace-first (list new-element)
   `(setf ,list (cons ,new-element ,list)))
REPLACE-FIRST
> (setf test-list '(a b c d))
(A B C D)
> (replace-first test-list 'k)
(K A B C D)
> test-list
(K A B C D)

but for various reasons (including all the negative ones about macros) I
wanted to do this with a real function.  If I could find some way to pass
a pointer to the symbol "test-list" and not what "test-list" points to, I
would be in good shape.

            Jeffrey