This one has me confused. I have a list of objects. Here is the
function to delete one of them:
(defun delete-transaction (index)
:documentation "Delete a transaction."
(decf index)
(with-tm *tm*
(setf transactions (delete (nth index transactions) transactions)))
; (delete (nth index transactions) transactions))
(format t "(tm) Transactions left: ~A~%" (count-transactions)))
'*tm*' is an object that holds transaction objects.
'transactions' is the list of transaction objects internal to *tm*.
This version of the function works as expected. But when I uncomment
the one line and comment out the setf line, it will never delete the
first (zeroth) entry. Why is this?
"jonathon" <···········@bigfoot.com> writes:
> This one has me confused. I have a list of objects. Here is the
> function to delete one of them:
>
> (defun delete-transaction (index)
> :documentation "Delete a transaction."
> (decf index)
> (with-tm *tm*
> (setf transactions (delete (nth index transactions) transactions)))
> ; (delete (nth index transactions) transactions))
> (format t "(tm) Transactions left: ~A~%" (count-transactions)))
>
> '*tm*' is an object that holds transaction objects.
> 'transactions' is the list of transaction objects internal to *tm*.
>
> This version of the function works as expected. But when I uncomment
> the one line and comment out the setf line, it will never delete the
> first (zeroth) entry. Why is this?
>
DELETE is destructive and:
"delete, when sequence is a list, is permitted to setf any part, car
or cdr, of the top-level list structure in that sequence. When
sequence is a vector, delete is permitted to change the dimensions of
the vector and to slide its elements into new positions without
permuting them to produce the resulting vector."
http://www.lispworks.com/documentation/HyperSpec/Body/f_rm_rm.htm
You should always set the location holding the sequence being modified.
/Jon
--
'j' - a n t h o n y at romeo/charley/november com
From: Kent M Pitman
Subject: Re: Having trouble deleting first item in list
Date:
Message-ID: <u8y0ulenb.fsf@nhplace.com>
"jonathon" <···········@bigfoot.com> writes:
> This one has me confused. I have a list of objects. Here is the
> function to delete one of them:
>
> (defun delete-transaction (index)
> :documentation "Delete a transaction."
> (decf index)
> (with-tm *tm*
> (setf transactions (delete (nth index transactions) transactions)))
> ; (delete (nth index transactions) transactions))
> (format t "(tm) Transactions left: ~A~%" (count-transactions)))
>
> '*tm*' is an object that holds transaction objects.
> 'transactions' is the list of transaction objects internal to *tm*.
>
> This version of the function works as expected. But when I uncomment
> the one line and comment out the setf line, it will never delete the
> first (zeroth) entry. Why is this?
You're experiencing the "DELETE bug".
You need to do
(setf transactions (delete (nth index transactions) transactions))
DELETE does not receive a pointer to the location that holds the list and
is unable to update it. You _must_ use the return value from DELETE and
not rely on DELETE for side-effect, since in the case that the element to
be deleted is the first element, DELETE will just _return_ the next tail of
the list that doesn't contain the to-be-deleted elements and will not
have a side-effect--there is no side-effect it could possibly have.
Kent M Pitman wrote:
> You _must_ use the return value from DELETE and
> not rely on DELETE for side-effect, since in the case that the element to
> be deleted is the first element, DELETE will just _return_ the next tail of
> the list that doesn't contain the to-be-deleted elements and will not
> have a side-effect--there is no side-effect it could possibly have.
Well, not necessarily. DELETE might have been implemented like this:
(defun delete (item list)
(cond
((null list) nil)
((eql (car list) item)
(cond
((null (cdr list)) nil)
(t
(setf (car list) (cadr list))
(setf (cdr list) (cddr list))
(delete item list)))
(t (setf (cdr list) (delete item (cdr list)))
list)))
The bug is unavoidable if there is nothing in the list except
the item to be deleted.
Paul
From: Kent M Pitman
Subject: Re: Having trouble deleting first item in list
Date:
Message-ID: <ur7elzx5l.fsf@nhplace.com>
"Paul F. Dietz" <·····@dls.net> writes:
> Kent M Pitman wrote:
>
> > You _must_ use the return value from DELETE and
> > not rely on DELETE for side-effect, since in the case that the element to
> > be deleted is the first element, DELETE will just _return_ the next tail of
> > the list that doesn't contain the to-be-deleted elements and will not
> > have a side-effect--there is no side-effect it could possibly have.
>
> Well, not necessarily. DELETE might have been implemented like this:
>
> (defun delete (item list)
> (cond
> ((null list) nil)
> ((eql (car list) item)
> (cond
> ((null (cdr list)) nil)
> (t
> (setf (car list) (cadr list))
> (setf (cdr list) (cddr list))
> (delete item list)))
> (t (setf (cdr list) (delete item (cdr list)))
> list)))
Yes, I've long known this. But
(a) this is makes predictable structure sharing unpredictable
(b) doesn't fix this bug:
> The bug is unavoidable if there is nothing in the list except
> the item to be deleted.
Given this, the above is an exercise in futility.
You still need the SETQ.
"jonathon" <···········@bigfoot.com> writes:
>This version of the function works as expected. But when I uncomment
>the one line and comment out the setf line, it will never delete the
>first (zeroth) entry. Why is this?
Because it cannot destructively remove the first element of a list.
You'd have to adjust the references in all variables pointing to that
list instead to do so.
If you visualize it on paper with the list in box-notation, you'll see
why this is so.
mkb.
If you're always deleting the first item in the list you could just do
:
(defun delete-first( lst )
(cdr lst))
(setf lst '( a b c 1 2 3 ))
(setf lst (delete-first lst))