From: Mark Carroll
Subject: Opposite of pushnew
Date: 
Message-ID: <cWg*Txx5n@news.chiark.greenend.org.uk>
I'm looking for a sort of opposite of pushnew, doing something
like this,

(defmacro remove-element (element our-list)
  `(setf ,our-list (set-difference ,our-list (list ,element))))

Is there a predefined macro I somehow missed, or a particularly nice
way of doing it? Just wondering. (-:

-- Mark

From: Erik Naggum
Subject: Re: Opposite of pushnew
Date: 
Message-ID: <3141561359871775@naggum.no>
* Mark Carroll <·····@chiark.greenend.org.uk>
| I'm looking for a sort of opposite of pushnew ...
: 
| Is there a predefined macro I somehow missed, or a particularly nice
| way of doing it? Just wondering. (-:

  this may be what you're looking for.  please note that neither preparing
  derivative works or making modifications are permitted by default.  (this
  is not free software in case that isn't obvious.)

(defmacro drop (object place &rest keys &key key test test-not &environment environment)
  "Drop a particular OBJECT from list in PLACE.  (Intended as counterpart to PUSH/-NEW.)
Copyright 1999 by Erik Naggum.  Verbatim inclusion and redistribution permitted.
For any other use, write <····@naggum.no> or call +47 8800 8879 or +1 510 435 8604."
  (declare (ignore key test test-not))
  (multiple-value-bind (vars vals store-vars writer reader)
      (get-setf-expansion place environment)
    (let ((evaled-value (gensym))
	  (store-var (first store-vars)))
      (if (cdr store-vars)
	`(let* ((,evaled-value ,object)
		,@(mapcar #'list vars vals))
	   (multiple-value-bind ,store-vars ,reader
	     (setq ,store-var (delete ,evaled-value ,store-var :count 1 ,@keys))
	     ,writer))
	`(let* ((,evaled-value ,object)
		,@(mapcar #'list vars vals)
		(,store-var (delete ,evaled-value ,reader :count 1 ,@keys)))
	   ,writer)))))

#:Erik
-- 
@1999-07-22T00:37:33Z -- pi billion seconds since the turn of the century
From: Thomas A. Russ
Subject: Re: Opposite of pushnew
Date: 
Message-ID: <ymihfmyc4r0.fsf@sevak.isi.edu>
Mark Carroll <·····@chiark.greenend.org.uk> writes:

> 
> I'm looking for a sort of opposite of pushnew, doing something
> like this,
> 
> (defmacro remove-element (element our-list)
>   `(setf ,our-list (set-difference ,our-list (list ,element))))
> 
> Is there a predefined macro I somehow missed, or a particularly nice
> way of doing it? Just wondering. (-:

There isn't any pre-defined macro, so your solution is close.  A slight
improvement would be to use REMOVE instead of SET-DIFFERENCE, since it
does what you want more directly:

(defmacro remove-element (element our-list)
   `(setf ,our-list (remove ,element ,our-list)))

Of course, there are potential problems with multiple evaluation of the
OUR-LIST form.  This example would fail for something like:

	(remove-element 'x (aref my-array (incf i)))

I'm not sure what the proper solution to this is, since the standard
technique of introducing a local variable to hold the result doesn't
work because you need a location, not a value, for the SETF form.

-Tom.

-- 
Thomas A. Russ,  USC/Information Sciences Institute          ···@isi.edu    
From: Kent M Pitman
Subject: Re: Opposite of pushnew
Date: 
Message-ID: <sfwg12hd7g9.fsf@world.std.com>
Mark Carroll <·····@chiark.greenend.org.uk> writes:

> I'm looking for a sort of opposite of pushnew, doing something
> like this,
> 
> (defmacro remove-element (element our-list)
>   `(setf ,our-list (set-difference ,our-list (list ,element))))
> 
> Is there a predefined macro I somehow missed, or a particularly nice
> way of doing it? Just wondering. (-:

No predefined macro.

Please make sure you use define-modify-macro.
You do not want to use the expansion you used here.

Think about: "double evaluation" problem (i.e., the case
 where our-list is a "place" with subforms that do side-effects,
 and where copying it to happen twice instead of once will 
 make the wrong number of side-effects.)
From: Pierre R. Mai
Subject: Re: Opposite of pushnew
Date: 
Message-ID: <87iu7d5xvl.fsf@orion.dent.isdn.cs.tu-berlin.de>
Kent M Pitman <······@world.std.com> writes:

> Mark Carroll <·····@chiark.greenend.org.uk> writes:
> 
> > I'm looking for a sort of opposite of pushnew, doing something
> > like this,
> > 
> > (defmacro remove-element (element our-list)
> >   `(setf ,our-list (set-difference ,our-list (list ,element))))
> > 
> > Is there a predefined macro I somehow missed, or a particularly nice
> > way of doing it? Just wondering. (-:
> 
> No predefined macro.
> 
> Please make sure you use define-modify-macro.
> You do not want to use the expansion you used here.

If you use define-modify-macro you can't easily get the argument order
to be the same as for push/pushnew though.  The macro defined via
define-modify-macro takes the place first:

(defun removef-internal (place item &rest options)
  (apply #'remove item place options))

(define-modify-macro removef (item &rest options) removef-internal)

And you can't easily wrap another macro around this to change the
argument order, since this violates the left-to-right evaluation order
rule:

;; Don't do this!  This will confuse programmers in the face of
;; side-effects!
(defmacro drop (item place &rest options)
  `(removef ,place ,item ,@options))

If I see it correctly, the only way to get push/pushnew-like argument
order is to do it the hard way via get-setf-expansion, etc. (see
Erik's posting).

Regs, Pierre.

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Amon Seagull
Subject: Re: Opposite of pushnew
Date: 
Message-ID: <7n7grs$6po$1@femto.cs.rochester.edu>
I apologize; I must be missing something.  What is the original poster
trying to accomplish that isn't covered by CL's 'delete'?
amon


Mark Carroll () wrote:
: I'm looking for a sort of opposite of pushnew, doing something
: like this,

: (defmacro remove-element (element our-list)
:   `(setf ,our-list (set-difference ,our-list (list ,element))))

: Is there a predefined macro I somehow missed, or a particularly nice
: way of doing it? Just wondering. (-:

: -- Mark
From: Stig Hemmer
Subject: Re: Opposite of pushnew
Date: 
Message-ID: <ekvd7xkfpvr.fsf@epoksy.pvv.ntnu.no>
·······@cs.rochester.edu (Amon Seagull) writes:
> I apologize; I must be missing something.  What is the original poster
> trying to accomplish that isn't covered by CL's 'delete'?

The problem was to change a variable (or rather, place).
DELETE just returns its result.

Now, DELETE is _allowed_ to change to original list structure to do
its job, but it isn't _required_ to.  

In most implementations this will mean that DELETEing the first
element of a list will just return the lists CDR, while DELETEing
later elements will mutate the list.

Some times you don't want to mutate the list structure, it could be
shared.  This means using REMOVE rather than DELETE.

So, except for the double evaluation,

(setf variable (remove element variable))

is what you want to do.

Stig Hemmer,
Jack of a Few Trades.
From: Mark Carroll
Subject: Re: Opposite of pushnew
Date: 
Message-ID: <Xhp*yZG5n@news.chiark.greenend.org.uk>
Thank you very much, people! That was certainly very educational. I'm
still getting used to figuring out what to do in Lisp when in other
languages I'd specify whether an argument was being passed wholly by
value, wholly by reference, or by a curious mixture of the two. (-:
Fortunately, speed isn't currently a concern...

-- Mark