Subject: Re: problem with delete
From: Erik Naggum <erik@naggum.net>
Date: 2000/10/02
Newsgroups: comp.lang.lisp
Message-ID: <3179481728635665@naggum.net>

* rolni104@ida.liu.se (Roland Nilsson)
| I'm having a weird problem with (delete item list).

  Nope.  You're having a minor problem understanding how lists are
  represented.  You're also having a minor misunderstanding of what it
  means for a Lisp function be destructive and have side effects.
  delete is one of those functions that have side effects as a side
  effect.  Its main effect is to return a list as per specification.
  (The streams functions have side effects as their main effect...)

| Consider:
| 
| (setq foo '(1 2 3 4 5))

  foo is a pointer to a cons cell containing 1 and a pointer to
                      a cons cell containing 2 and a pointer to
                      a cons cell containing 3 and a pointer to
                      a cons cell containing 4 and a pointer to
                      a cons cell containing 5 and nil.

| (when (my-test-for-deletion)
|    (delete 1 foo))
| 
| Ok, here delete should modify foo, so that
| 
|   foo => (2 3 4 5)

  delete does not modify variables, _ever_.  That would be the macro
  setq/setf (or any of the other macros that use setq/setf).

  delete modifies the structure of the internal pointers in the list
  structure.  Say you delete 3 from the list.  foo is a pointer to
  a cons cell containing 1 and a pointer to
  a cons cell containing 2 and a pointer to
  a cons cell containing 4 and a pointer to
  a cons cell containing 5 and nil.

  As a special case, if the first element of a list is to be deleted,
  which pointer needs to be modified in order to reflect the missing
  element?  Hint: _not_ one of the poiners in the list structure.

| Also, the delete clause should evaluate to this. For me, delete
| *does* return this result, but it *does not* modify the list, i.e.

  Bingo!  Use the value it returns, then.  Never use delete for its
  side effect (unless you know exceptionally well what you're doing).

|   (delete 1 foo) => (2 3 4 5), but still
|   foo => (1 2 3 4 5)

  Of course.  foo points to the cons cell that contains 1 and a
  pointer to the cons cell that contains 2 and ...  For delete to work
  the way you seem to want, it would have to rearrange the entire
  top-level list structure.

| For example, (setf foo (delete 1 foo)) does what's intended. It's
| like delete is acting like remove, non-destructive, in this case.

  Um, no.  "Destructive" means that while building the result it is
  free to reuse the resources that were used in one (or more) of the
  arguments.

(let ((foo (list 1 2 3 4 5)))
  (values (eq (cdr foo) (remove 1 foo))
	  (eq (cdr foo) (delete 1 foo))))

  This should return as two values nil and t.  Explain why.

  Why don't you write your own delete function that behaves the way
  you want, then try to understand how delete has been implemented,
  and argue for both designs and implementations?

#:Erik
-- 
  If this is not what you expected, please alter your expectations.