Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Looking for a LISP function or macro ...

52 views
Skip to first unread message

nc...@hotmail.com

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
Hi,

Thanks for the quick responses on my error handling question! They helped a
lot. I have another question. Is there a function or macro which will do
similar to what member-if does, but instead will return every element which
passes the test?

For example

>(this_function #'oddp '(1 2 3 4 5 6 7))
(1 3 5 7)

or

>(this_function #'integerp '(1 a 2 b 3 c))
(1 2 3)

I tried
>(mapcar #'(lambda (x) (if (oddp x) x nil)) '(1 2 3 4 5 6 7))
but I got
(1 NIL 3 NIL 5 NIL 7)

I guess I could write a function to do it, but I think there might an existing
one out there which will perform this? It seems like it would be a common
operation on a list right?

Again, thanks for your help.

NC

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum

Barry Margolin

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
In article <6ttrts$qjk$1...@nnrp1.dejanews.com>, <nc...@hotmail.com> wrote:
>Thanks for the quick responses on my error handling question! They helped a
>lot. I have another question. Is there a function or macro which will do
>similar to what member-if does, but instead will return every element which
>passes the test?

Use REMOVE-IF and invert the sense of the test (using the COMPLEMENT
function, if necessary). This supercedes the deprecated REMOVE-IF-NOT
function.

>>(this_function #'oddp '(1 2 3 4 5 6 7))
>(1 3 5 7)

(remove-if #'evenp '(1 2 3 4 5 6 7))

>>(this_function #'integerp '(1 a 2 b 3 c))
>(1 2 3)

(remove-if (complement #'integerp) '(1 a 2 b 3 c))

--
Barry Margolin, bar...@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.

Martti Halminen

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
nc...@hotmail.com wrote:

> I have another question. Is there a function or macro which will do
> similar to what member-if does, but instead will return every element which
> passes the test?
>

> For example


>
> >(this_function #'oddp '(1 2 3 4 5 6 7))
> (1 3 5 7)
>

> or


>
> >(this_function #'integerp '(1 a 2 b 3 c))
> (1 2 3)
>

> I tried
> >(mapcar #'(lambda (x) (if (oddp x) x nil)) '(1 2 3 4 5 6 7))
> but I got
> (1 NIL 3 NIL 5 NIL 7)

If you want to play with mapping, something like this might work:

(mapcan #'(lambda (x) (if (oddp x) (list x) nil)) '(1 2 3 4 5 6 7))

Another way would be:

(loop for i in '(1 2 3 4 5 6 7) when (oddp i) collect i)

> I guess I could write a function to do it, but I think there
> might an existing
> one out there which will perform this? It seems like it would
> be a common
> operation on a list right?

You're right. It does already exist:

(remove-if-not #'oddp '(1 2 3 4 5 6 7))


--
________________________________________________________________
^. Martti Halminen
/ \`. Design Power Europe Oy
/ \ `. Tekniikantie 12, FIN-02150 Espoo, Finland
/\`. \ | Tel:+358 9 4354 2306, Fax:+358 9 455 8575
/__\|___\| Mailto:Martti....@dpe.fi http://www.dpe.fi

Thomas A. Russ

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
nc...@hotmail.com writes:

>
> Hi,


>
> Thanks for the quick responses on my error handling question! They helped a

> lot. I have another question. Is there a function or macro which will do


> similar to what member-if does, but instead will return every element which
> passes the test?

How about remove-if-not?

(remove-if-not #'oddp '(1 2 3 4 5 6 7 8))

=> (1 3 5 7)

> I tried
> >(mapcar #'(lambda (x) (if (oddp x) x nil)) '(1 2 3 4 5 6 7))
> but I got
> (1 NIL 3 NIL 5 NIL 7)

This is pretty close. You would have to use mapcaN instead of mapcaR
and turn the value you want to collect into a list:

(mapcan #'(lambda (x) (if (oddp x) (list x) nil)) '(1 2 3 4 5 6 7 8))

=> (1 3 5 7)

> I guess I could write a function to do it, but I think there might an existing
> one out there which will perform this? It seems like it would be a common
> operation on a list right?

I seems you will need to get your hands on a Common Lisp manual. It
will help solve most of these problems.

BTW there is also a simple iterative solution using loop:

(loop for i in '(1 2 3 4 5 6 7 8)


when (oddp i) collect i)

--
Thomas A. Russ, USC/Information Sciences Institute t...@isi.edu

Erik Naggum

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
* Barry Margolin <bar...@bbnplanet.com>

| Use REMOVE-IF and invert the sense of the test (using the COMPLEMENT
| function, if necessary). This supercedes the deprecated REMOVE-IF-NOT
| function.

I find this a conceptually horrible suggestion. REMOVE-IF-NOT is at
least possible to deal with as an idiom. REMOVE-IF of the COMPLEMENT of
the function I really want in order to _keep_ certain elements is exactly
how I would have force people to do things if I were into purity for its
own sake and thought utility and pragmatics were stupid concerns.

not wanting to deal with the very annoying COMPLEMENT function, I have
defined functions COLLECT and RETAIN as the semantic complements of
REMOVE and DELETE, with -IF _and_ -IF-NOT variants. (COLLECT is a whole
lot different from REMOVE with some keyword arguments, by the way.)

(defun collect-if (predicate list &rest keys)
"Return a list of each element from LIST that satisfies PREDICATE.
Accepts the same keyword arguments as REMOVE-IF."
(apply #'remove-if-not predicate list keys))

I see no reason at all to deprecate -IF-NOT. the reason for deprecating
:TEST-NOT is in a whole different category, since it is unspecified what
:TEST FOO :TEST-NOT BAR should mean, i.e., when specified at the same
time, and this problem _does_ come up when applying a function an unknown
list of keyword-value pairs. no such thing could ever happen to -IF-NOT
functions, yet it is apparent from the write-ups that -IF-NOT only got
deprecated out of some misguided sense of symmetry with :TEST-NOT.

incidentally, the above function can be written with REMOVE-IF and the
annoying COMPLEMENT function if one is so inclined. in any case, I think
that if you think you need COMPLEMENT, you should define a new function
that conveys the new purpose, and use that instead. it may well use
COMPLEMENT internally. whether the new function is the test function or
the caller of the test function depends on the purpose. the same goes
for the all the other function-building functions that Dylan has and
which it's sort of fun to play with, but which I think should not be used
as open-coded idioms -- better to use them in implementations of
something that reflects how you think.

#:Erik
--
ATTENTION, all abducting aliens! you DON'T need to RETURN them!

nc...@hotmail.com

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
Hi,

Again, thanks for the answers! Remove-if-not is exactly what I was looking
for. This forum is great! Have a nice weekend!

Barry Margolin

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to
In article <31151336...@naggum.no>, Erik Naggum <er...@naggum.no> wrote:
>* Barry Margolin <bar...@bbnplanet.com>
>| Use REMOVE-IF and invert the sense of the test (using the COMPLEMENT
>| function, if necessary). This supercedes the deprecated REMOVE-IF-NOT
>| function.
>
> I find this a conceptually horrible suggestion.

It wasn't a suggestion, it was simply a statement of fact: ANSI CL
specifies that the -IF-NOT functions are all deprecated. This was done as
a concession to people who felt the language was bloated with unnecessary
functions. Of course, there's nothing preventing the standards committee
reversing itself in the future; if people ignore the deprecation and
continue to make use of the -IF-NOT functions, it would make sense for the
standard to agree with common practice, rather than gratuitously breaking
everyone's code by removing them. On the other hand, if they do go through
with removing them, users can't say they weren't warned years in advance.

David J Cooper Jr

unread,
Sep 18, 1998, 3:00:00 AM9/18/98
to

;;
;; Based on the function ``filter'' from pg. 105 of Graham ``ANSI Common Lisp''
;;

(defun filter-in (fn lst)
(let ((acc nil))
(dolist (x lst (nreverse acc))
(when (funcall fn x)
(push x acc)))))


--
David J Cooper Jr Genworks International
dcoo...@genworks.com http://www.genworks.com

...Embracing an Open Systems Approach to Knowledge-based Engineering...
--
David J Cooper Jr Genworks International
dcoo...@genworks.com http://www.genworks.com

...Embracing an Open Systems Approach to Knowledge-based Engineering...

Kent M Pitman

unread,
Sep 19, 1998, 3:00:00 AM9/19/98
to
Barry Margolin <bar...@bbnplanet.com> writes:

> In article <31151336...@naggum.no>, Erik Naggum <er...@naggum.no> wrote:
> >
> > I find this a conceptually horrible suggestion.

So would I if not for the fact that these functions (or even their
negations) aren't used much, and are totally easy to write yourself
if missing.

It's clear the :TEST-NOT arguments are a semantic problem that has to be
removed. (To see why, think about what happens when both :TEST-NOT and
:TEST are supplied.) But the -IF-NOT functions are in more of a gray
area. They are not semantically bankrupt--just rarely used. Perhaps
by the time any change could be made, the space they take up will be of
less importance.

> if they do go through
> with removing them, users can't say they weren't warned years in advance.

Precisely. It's not a promise to remove them. It just reserves the
right to discuss it without breaking people's programs.

And users aren't exactly screwed if they do go away some year. I
didn't test the following, but imagine it or something like it would
work, both today and years from now when remove-if-not goes away.

(eval-when (:execute :compile-toplevel :load-toplevel)
(when (fboundp 'remove-if-not)
(pushnew :remove-if-not *features*)))

#-remove-if-not
(proclaim '(inline remove-if-not)) ;avoid overhead of extra function call

#-remove-if-not
(defun remove-if-not (predicate sequence &rest keys &key &allow-other-keys)
(apply #'remove-if (complement predicate) sequence keys))


Or, more generally, but still equally untested...

(defmacro define-if-not (not-function function)
;; Slight kludge warning: This assumes a compile-time check is good
;; enough. In principle, the compile time might differ from the
;; runtime, and normally one doesn't make the test for a runtime
;; situation at compile-time, but in the case of standards, the
;; compiler and run-time usually agree.
(unless (fboundp not-function) ; assume compile-time check is close enough
`(progn
(proclaim '(inline ,not-function))
(defun ,not-function (predicate sequence &rest keys &key &allow-other-keys)
(apply #',function (complement predicate) sequence keys))
',not-function)))

(define-if-not remove-if-not remove-if)
(define-if-not delete-if-not delete-if)
...etc.

Anyway, my point is that the few users who even use these functions
can EASILY compensate for their absence. And probably, if/when we do
remove them, we'll somewhere publish the workaround code so users
don't even have to do that much work.

Erik Naggum

unread,
Sep 19, 1998, 3:00:00 AM9/19/98
to
* Kent M Pitman <pit...@world.std.com>

| So would I if not for the fact that these functions (or even their
| negations) aren't used much, and are totally easy to write yourself
| if missing.

"it's easy to write it yourself" is the Scheme argument. for a single
function, it's hard to refute, except for "why _should_ programmers
everywhere need to do it for themselves?". multiplied by thousands of
functions, it doesn't really work that well, anymore. moreover, I have
yet to see an implementation that does away with the closure consing and
function call overhead of COMPLEMENT in _all_ cases, which I doubt is
even possible, so to write these functions _well_ would require writing
the internals yourself, or you penalize people for their needs. that's
not what I associate with Common Lisp.

a quick scan of my last project's source (120K, kept small through very
hard work), shows that I found these -IF-NOT functions useful:

DELETE-IF-NOT of UPPER-CASE-P, to retain initials
REMOVE-IF-NOT of UPPER-CASE-P
POSITION-IF-NOT of WHITESPACE-CHAR-P (for a non-consing TRIM)
MEMBER-IF-NOT of EMPTY, a test for a blank line, etc
and of NULL, to remove initial NILs in a list

in all of these cases, I would either cons up a closure with COMPLEMENT,
write a new function with the reversed sense without closure consing or
extra function call overhead, or _hope_ there's a compiler macro that
reverts to internal -IF-NOT functions. what, precisely, is gained by
removing these functions? I'd say "purity of design", and that would
have been valid if such was an expressed goal of the language, and it
didn't have serious costs associated with it.



| It's clear the :TEST-NOT arguments are a semantic problem that has to be
| removed.

as I have already stated, but once again for the record: :TEST-NOT should
go, and this I have thought for years. removing :TEST-NOT would not be
done out of "purity of design" concerns, but out of concern for the fuzzy
semantics of specifying both :TEST and :TEST-NOT, which might easily
happen when writing the kind of functions that are suggested replacements
for REMOVE-IF-NOT. since that is possible, we have a real conflict that
cries out for a solution. I don't _like_ the name "complement" at all,
but if I can bury it sufficiently, I hope I won't notice it sticking out.

| And users aren't exactly screwed if they do go away some year. I
| didn't test the following, but imagine it or something like it would
| work, both today and years from now when remove-if-not goes away.
|
| (eval-when (:execute :compile-toplevel :load-toplevel)
| (when (fboundp 'remove-if-not)
| (pushnew :remove-if-not *features*)))
|
| #-remove-if-not
| (proclaim '(inline remove-if-not)) ;avoid overhead of extra function call
|
| #-remove-if-not
| (defun remove-if-not (predicate sequence &rest keys &key &allow-other-keys)
| (apply #'remove-if (complement predicate) sequence keys))

once upon a time, you said something to the effect that Common Lisp saved
you heaps of code that you previously had had to add to every project.
we're moving backwards, now, where people have to add such code. users
_are_ screwed in many ways by this COMPLEMENT business. debuggability
goes down, performance is hit, etc, etc. to re-supply REMOVE-IF-NOT
after X3J13 takes it away needs reimplementing the function, not just
slapping a couple wrappers around existing functions and hope nobody will
notice that they can no longer fix bugs in the predicate function and
continue, or that APPLY crops up much more often than it should during
profiling. an implementation that sports compiler macros that attempt to
make REMOVE-IF fast by pre-determining keyword arguments would not be
able to optimize the call unless COMPLEMENT itself were to be used in the
_actual_ form. thus, you make code much less readable in order to save
on a "bloat" factor that is about two order of magnitude smaller than
that of C++ or Java.

| Anyway, my point is that the few users who even use these functions can
| EASILY compensate for their absence.

I take it that no study of the effects of the introduction of COMPLEMENT
has been made. COMPLEMENT has _very_ high costs. they have _not_ been
defended, nor have they been compared to the gains from removing -IF-NOT,
if any. as I see it, COMPLEMENT is a wanton waste of resources. I have
no qualms about spending lots of resources for a good reason; it's only
the _wanton_ part I object to.

| And probably, if/when we do remove them, we'll somewhere publish the
| workaround code so users don't even have to do that much work.

well, _I'm_ certain that vendors will protect user investments even if
the committee abandons that goal.

take :TEST-NOT and be satisfied, is my suggestion. don't touch -IF-NOT.

Reini Urban

unread,
Sep 19, 1998, 3:00:00 AM9/19/98
to
Erik Naggum <er...@naggum.no> wrote:
> I find this a conceptually horrible suggestion. REMOVE-IF-NOT is at
> least possible to deal with as an idiom. REMOVE-IF of the COMPLEMENT of
> the function I really want in order to _keep_ certain elements is exactly
^^^^^^

> how I would have force people to do things if I were into purity for its
> own sake and thought utility and pragmatics were stupid concerns.

the readability argument:
instead of your collect-if I named mine KEEP-IF. this a LOT more
readable than remove-if-not, which is itself a lot more readable than
(remove-if (complement ..) ..) or the :TEST-NOT key
reading negations instead of their positive synonyms is like watching a
woody allen movie.

but collect-if is also a good name. i just watched myself reading my
code with the unspoken words "keep if" so i named it like this. you,
erik, explained it the same way :)

---
Reini Urban
http://xarch.tu-graz.ac.at/autocad/news/faq/autolisp.html

Erik Naggum

unread,
Sep 19, 1998, 3:00:00 AM9/19/98
to
* Reini Urban <rur...@sbox.tu-graz.ac.at>

| but collect-if is also a good name. i just watched myself reading my
| code with the unspoken words "keep if" so i named it like this. you,
| erik, explained it the same way :)

hm. I intended "keep" as a generalized term encompassing both "collect"
and "retain", the point being that COLLECT would return a freshly consed
list of elements collected from the argument list, while RETAIN would
(destructively) delete the unwanted elements from the argument list.

Jeffrey Mark Siskind

unread,
Sep 19, 1998, 3:00:00 AM9/19/98
to Kent M Pitman
But the -IF-NOT functions are in more of a gray
> area. They are not semantically bankrupt--just rarely used.

I personally find that I use REMOVE-IF-NOT *much* more than REMOVE-IF. And I
personally find that REMOVE-IF-NOT is conceptually more of a primitive than
REMOVE-IF. The name not withstanding. REMOVE-IF-NOT is often called by other
names: e.g. FILTER, SUCH-THAT, etc. More often than not, I find that I want a
list of elements that satisfies some predicate (which is what REMOVE-If-NOT
yields), not a list of elements that does not satisfy some predicate (which is
what REMOVE-IF yields).

The issue is whether to view the function operationally (what to remove) or
declaratively (what property the result has). I personally prefer the later
and find that it makes code more readable.

Jeff (http://www.neci.nj.nec.com/homepages/qobi)

David D. Smith

unread,
Sep 21, 1998, 3:00:00 AM9/21/98
to
In article <31151852...@naggum.no>, Erik Naggum <er...@naggum.no> wrote:

> * Kent M Pitman <pit...@world.std.com>
> | So would I if not for the fact that these functions (or even their
> | negations) aren't used much, and are totally easy to write yourself
> | if missing.
>
> "it's easy to write it yourself" is the Scheme argument. for a single
> function, it's hard to refute, except for "why _should_ programmers
> everywhere need to do it for themselves?". multiplied by thousands of
> functions, it doesn't really work that well, anymore. moreover, I have
> yet to see an implementation that does away with the closure consing and
> function call overhead of COMPLEMENT in _all_ cases, which I doubt is
> even possible, so to write these functions _well_ would require writing
> the internals yourself, or you penalize people for their needs. that's
> not what I associate with Common Lisp.

I second this POV and will also say that I frequently use local functions
as these arguments, which tends to compound the problem.

> a quick scan of my last project's source (120K, kept small through very
> hard work), shows that I found these -IF-NOT functions useful:
>
> DELETE-IF-NOT of UPPER-CASE-P, to retain initials
> REMOVE-IF-NOT of UPPER-CASE-P
> POSITION-IF-NOT of WHITESPACE-CHAR-P (for a non-consing TRIM)
> MEMBER-IF-NOT of EMPTY, a test for a blank line, etc
> and of NULL, to remove initial NILs in a list

A review of our Paracell Navigator shows 17 calls to -IF-NOT functions,
including COUNT, REMOVE, DELETE, POSITION, MEMBER, and FIND. Additionally
there are 10 calls using :TEST-NOT.

> in all of these cases, I would either cons up a closure with COMPLEMENT,
> write a new function with the reversed sense without closure consing or
> extra function call overhead, or _hope_ there's a compiler macro that
> reverts to internal -IF-NOT functions. what, precisely, is gained by
> removing these functions? I'd say "purity of design", and that would
> have been valid if such was an expressed goal of the language, and it
> didn't have serious costs associated with it.

If "purity of design", whatever that means, ever becomes the primary goal
in the specification of Common LISP, it will be doomed as a commercial
language. I am a pragmatists of a sort and I use Common LISP because I get
the the most work done for the least time spent. Please don't make me
waste the time to reinvent all those functions and features that others
have done so well, just because it satisfies someones notion of "purity of
design".

> | It's clear the :TEST-NOT arguments are a semantic problem that has to be
> | removed.

Kent,

It is not at all clear to me. If you are concerned with the overhead it
implies, I would suggest the following: Change the simultaneous :TEST /
:TEST-NOT problem from an ERROR to a case of "Undefined Behavior" and let
the user accept responsibility for it, with the implementation free to
pick the leftmost perhaps.

As I showed you (about 10 years ago at Encore), and showed others on the
list here. All the -IF-NOT functions can be implemented in terms of
:TEST-NOT #'FUNCALL. As can the -IF functions in terms of :TEST
#'FUNCALL. This is another reason why the Space argument is a less
persuasive reason to expunge these. BTW, I noticed at the time (at
Encore) that Lucid had big huge expansions for each of the -IF and -IF-NOT
functions, with no code sharing...

Documentation is DONE.

Maintenence is hardly required for these functions.

d

Kent M Pitman

unread,
Sep 21, 1998, 3:00:00 AM9/21/98
to
d...@flavors.com (David D. Smith) writes:

> [...] If you are concerned with the overhead it


> implies, I would suggest the following: Change the simultaneous :TEST /
> :TEST-NOT problem from an ERROR to a case of "Undefined Behavior" and let
> the user accept responsibility for it, with the implementation free to
> pick the leftmost perhaps.

No. The time part doesn't bother me at all. It's that I think having both
creates an aomalous situation where if someone does
(defun frob (&rest keys) (apply #'find-if :test #'eql keys))
which is the normal idiom for overriding a :test argument in a set of keys,
you don't know if you really merged it right. This isn't about efficiency,
it's about predictability. THere is an efficiency argument, but I
don't find it the key issue. To me, the "undefined" ploy is only allowable
when normal uses allow you to tell you're doing it.

Keyword cascading/overriding may not be common among readers of this list,
I don't know; but I know places where it's very common. We were really
fixing a bug in fixing the :test and :test-not stuff. The same can't be said
of -IF-NOT, which I identified as being in a gray area and which I
think the committee deprecated mostly for perceived consistency.

(Wouldn't be the first time we got it wrong on "apparent consistency".
The one that drives me nuts is the "you can't repeat an argument in a
bound variable list" rule as applied to LET*, for which you really ought
to be able to.)

FWIW, I'm pretty much swayed by very useful evidence
offered in this discussion that the -IF-NOT functions should not go
away. So anyone who wants to argue for keeping them isn't talking to me.

Gareth McCaughan

unread,
Sep 22, 1998, 3:00:00 AM9/22/98
to
Kent Pitman wrote:

> No. The time part doesn't bother me at all. It's that I think having both
> creates an aomalous situation where if someone does
> (defun frob (&rest keys) (apply #'find-if :test #'eql keys))
> which is the normal idiom for overriding a :test argument in a set of keys,
> you don't know if you really merged it right. This isn't about efficiency,
> it's about predictability.

I don't understand why this wouldn't be solved perfectly adequately
by saying that the *rightmost* :TEST or :TEST-NOT takes precedence.

--
Gareth McCaughan Dept. of Pure Mathematics & Mathematical Statistics,
gj...@dpmms.cam.ac.uk Cambridge University, England.

0 new messages