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

remove-if-not, still allowed or considered to be verbotten?

299 views
Skip to first unread message

Yves S. Garret

unread,
Sep 18, 2012, 1:45:38 PM9/18/12
to
I'm going through PCL and now on Chapter 11:

http://gigamonkeys.com/book/collections.html

I found this portion:

"
According to the language standard, the -IF-NOT variants are deprecated. However, that deprecation is generally considered to have itself been ill-advised. If the standard is ever revised, it's more likely the deprecation will be removed than the -IF-NOT functions. For one thing, the REMOVE-IF-NOT variant is probably used more often than REMOVE-IF. Despite its negative-sounding name, REMOVE-IF-NOT is actually the positive variant--it returns the elements that do satisfy the predicate.
"

Is there a general consensus (preference, understanding, whatever) on whether -if-not is preferred or -if, but having the method that you're using wrapped in (complement #'function-test)?

Pascal Costanza

unread,
Sep 18, 2012, 1:59:43 PM9/18/12
to
REMOVE-IF-NOT is not particularly hard to understand, and its semantics
are not problematic in any way. It's also fewer characters to type than
the alternatives, so it's definitely fine to use it.

COMPLEMENT is funky, IMO. But hey, if prefer that, go ahead...


Pascal

--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
The views expressed are my own, and not those of my employer.

Yves S. Garret

unread,
Sep 18, 2012, 2:05:01 PM9/18/12
to
I don't have an issue with how to use it, merely wondering if it's something that should be avoided or actively used :-) .

RG

unread,
Sep 18, 2012, 2:26:26 PM9/18/12
to
In article <3b11dd1a-baad-4567...@googlegroups.com>,
It doesn't matter because:

1. The standard will never be revised

2. Even if the standard were revised, adding remove-if-not at the used
level is an elementary exercise.

So if you like remove-if-not, use it. Otherwise don't.

Personally, I think the right name for REMOVE-IF-NOT is FILTER.

You might also want to consider using list comprehensions and iterators:

http://blog.rongarret.info/2008/02/joy-of-iterators.html

rg

Pascal J. Bourguignon

unread,
Sep 18, 2012, 2:38:10 PM9/18/12
to
"Yves S. Garret" <yoursurr...@gmail.com> writes:

> I don't have an issue with how to use it, merely wondering if it's
> something that should be avoided or actively used :-) .

No, you can use either

(remove-if-not predicate sequence)
or
(remove-if (complement predicate) sequence)

Notice that often predicate is a lambda form, and therefore you can
invert the condition returned by the predicate. Instead of:

(remove-if-not (lambda (x) (or (zerop (mod x 3)) (zerop (mod x 5))))
sequence)

you can write:

(remove-if (lambda (x) (and (/= 0 (mod x 3)) (/= 0 (mod x 5))))
sequence)

But notice also that instead of using lambda forms, you can collect a
library of utility high order functions such as:

(defun there-is (&rest funs)
(lambda (&rest args)
(every (lambda (fun) (apply fun args)) funs)))

(defun rcurry (fun &rest right-args)
(lambda (&rest left-args)
(apply fun (append left-args right-args))))

(defun compose (fun &rest funs)
(if funs
(lambda (&rest args)
(funcall fun (apply (apply (function compose) funs) args)))
fun))

(defun iota (max &key (start 0) (step 1))
(loop for i :from start :to max :by step collect i))

;; Some of them are already in alexandria or some other libraries.


So that you can write it, without using any variable or parameter:

(remove-if (complement (there-is (compose (function zerop) (rcurry (function mod) 3))
(compose (function zerop) (rcurry (function mod) 5))))
(iota 40))
--> (0 15 30)

(remove-if-not (there-is (compose (function zerop) (rcurry (function mod) 3))
(compose (function zerop) (rcurry (function mod) 5)))
(iota 40))
--> (0 15 30)


--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.

RG

unread,
Sep 18, 2012, 3:31:36 PM9/18/12
to
In article <rNOSPAMon-21ACE...@news.albasani.net>,
That should be "user" not "used."

Stefan Mandl

unread,
Sep 18, 2012, 3:48:38 PM9/18/12
to
RG <rNOS...@flownet.com> writes:

> Personally, I think the right name for REMOVE-IF-NOT is FILTER.

Me too.

Teemu Likonen

unread,
Sep 19, 2012, 12:29:17 AM9/19/12
to
RG [2012-09-18 11:26:26 -0700] wrote:

> Personally, I think the right name for REMOVE-IF-NOT is FILTER.

Personally I wouldn't know if FILTER means REMOVE-IF or REMOVE-IF-NOT.

(filter #'numberp sequence)

Does that filter numbers out or just leave numbers?

Kaz Kylheku

unread,
Sep 19, 2012, 1:06:33 AM9/19/12
to
On 2012-09-19, Teemu Likonen <tlik...@iki.fi> wrote:
> RG [2012-09-18 11:26:26 -0700] wrote:
>
>> Personally, I think the right name for REMOVE-IF-NOT is FILTER.
>
> Personally I wouldn't know if FILTER means REMOVE-IF or REMOVE-IF-NOT.

Those are not the only two possible meanings. Filter could mean retain,
remove, but it has also come to mean to alter through an arbitrary function.

> (filter #'numberp sequence)
>
> Does that filter numbers out or just leave numbers?

Or is it a new name for (mapcar #'numberp sequence), like
first and rest for car and cdr?

Barry Margolin

unread,
Sep 19, 2012, 1:27:15 AM9/19/12
to
In article <3b11dd1a-baad-4567...@googlegroups.com>,
"Yves S. Garret" <yoursurr...@gmail.com> wrote:

> I don't have an issue with how to use it, merely wondering if it's something
> that should be avoided or actively used :-)

Since the chance of the Common Lisp standard ever being revised is
epsilon, you can do whatever you want.

--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***

Elias Mårtenson

unread,
Sep 19, 2012, 1:54:28 AM9/19/12
to
On Wednesday, 19 September 2012 12:29:20 UTC+8, Teemu Likonen wrote:
> RG [2012-09-18 11:26:26 -0700] wrote:
>
>
>
> > Personally, I think the right name for REMOVE-IF-NOT is FILTER.
>
>
>
> Personally I wouldn't know if FILTER means REMOVE-IF or REMOVE-IF-NOT.

If we're talking about a hypothetical rename that will never happen, here's another suggestion:

KEEP-IF

RG

unread,
Sep 19, 2012, 2:35:56 AM9/19/12
to
In article <dd3053ee-17fa-42cc...@googlegroups.com>,
I like FILTER not because its meaning is self-evident but because it's a
universal convention in the functional programming world that filter
means remove-if-not. But KEEP-IF is good to.

Or we could go with DONT-REMOVE-IF-NOT-NULL.

rg

Pascal J. Bourguignon

unread,
Sep 19, 2012, 3:06:27 AM9/19/12
to
RG <rNOS...@flownet.com> writes:

> I like FILTER not because its meaning is self-evident but because it's a
> universal convention in the functional programming world that filter
> means remove-if-not. But KEEP-IF is good to.

Then an even better word than FILTER would be: DEMETER-IN-THE-FIELDS


http://en.memory-alpha.org/wiki/Tamarian_language

Kaz Kylheku

unread,
Sep 19, 2012, 3:15:42 AM9/19/12
to
Ah yes, nice name. I put such a function into TXR Lisp, as well as a lazy
workalike called keep-if*.

(The : symbol in lambda lists denotes the start of optional parameters.
A rest param is introduced by a consing dot.)

Functions remove-if, keep-if, remove-if* and keep-if*
Syntax:

(remove-if <predicate-function> <list> : <key-function>)
(keep-if <predicate-function> <list> : <key-function>)
(remove-if* <predicate-function> <list> : <key-function>)
(keep-if* <predicate-function> <list> : <key-function>)

Description

The remove-if function produces a list whose contents are those
of <list> but with those elements removed which satisfy <predi-
cate-function>. Those elements which are not removed appear in
the same order. The result list may share substructure with the
input list, and may even be the same list object if no items are
removed.

The optional <key-function> specifies how each element from the
<list> is transformed to an argument to <predicate-function>. If
this argument is omitted or specified as nil, then the predicate
function is applied to the elements directly, a behavior which
is identical to <key-function> being (fun identity).

The keep-if function is exactly like remove-if, except the sense
of the predicate is inverted. The function keep-if retains those
items which remove-if will delete, and removes those that
remove-if will preserve.

The remove-if* and keep-if* are like remove-if and keep-if, but
produce lazy lists.

Examples:

;; remove any element numerically equal to 3.
(remove-if (op = 3) '(1 2 3 4 3.0 5)) -> (1 2 4 5)

;; remove those pairs whose first element begins with "abc"
[remove-if (op equal [@1 0..3] "abc")
'(("abcd" 4) ("defg" 5))
car]
-> (("defg 5))

;; equivalent, without key function
(remove-if (op equal [(car @1) 0..3] "abc")
'(("abcd" 4) ("defg" 5)))
-> (("defg 5))

Kaz Kylheku

unread,
Sep 19, 2012, 3:27:23 AM9/19/12
to
Haha, check this.

In the GNU Make language (which I hardly need point out is more popular and
widely used than any functional language) you have these:

$(filter pattern...,text)
Returns all whitespace-separated words in text that do match any
of the pattern words, removing any words that do not match. The
patterns are written using ‘%’, just like the patterns used in
the patsubst function above.

[ snip examples ]

$(filter-out pattern...,text)
Returns all whitespace-separated words in text that do not match
any of the pattern words, removing the words that do match one or
more. This is the exact opposite of the filter function.

WJ

unread,
Oct 17, 2012, 7:44:54 AM10/17/12
to
Pascal Costanza wrote:

> On 18/09/2012 19:45, Yves S. Garret wrote:
> > I'm going through PCL and now on Chapter 11:
> >
> > http://gigamonkeys.com/book/collections.html
> >
> > I found this portion:
> >
> > "
> > According to the language standard, the -IF-NOT variants are deprecated. However, that deprecation is generally considered to have itself been ill-advised. If the standard is ever revised, it's more likely the deprecation will be removed than the -IF-NOT functions. For one thing, the REMOVE-IF-NOT variant is probably used more often than REMOVE-IF. Despite its negative-sounding name, REMOVE-IF-NOT is actually the positive variant--it returns the elements that do satisfy the predicate.
> > "
> >
> > Is there a general consensus (preference, understanding, whatever) on whether -if-not is preferred or -if, but having the method that you're using wrapped in (complement #'function-test)?
>
> REMOVE-IF-NOT is not particularly hard to understand, and its semantics are not problematic in any way. It's also fewer characters to type than the alternatives, so it's definitely fine to use it.
>
> COMPLEMENT is funky, IMO. But hey, if prefer that, go ahead...
>
>
> Pascal

Instead of using DARPA CL, let's use a Lispy language.

Racket:

: (filter even? '(0 1 2 3 4))
'(0 2 4)

WJ

unread,
Oct 17, 2012, 8:56:56 AM10/17/12
to
Excellent suggestion, much more in keeping with the
DARPA CL philosophy.

"Do you not never read no newspapers?" (Midnight Manhunt)

WJ

unread,
Oct 17, 2012, 9:45:20 AM10/17/12
to
Why this is marked as abuse? It has been marked as abuse.
Report not abuse
Instead of DARPA CL, let's use a Lispy language.

Racket:

(define (divisors? xs x)
(andmap (compose zero? (curry modulo x)) xs))
(filter (curry divisors? '(3 5)) (build-list 40 values))
--> '(0 15 30)

WJ

unread,
Oct 17, 2012, 3:21:01 PM10/17/12
to
Why this is marked as abuse? It has been marked as abuse.
Report not abuse
Pascal J. Bourguignon wrote:

> RG <rNOS...@flownet.com> writes:
>
> > I like FILTER not because its meaning is self-evident but because it's a
> > universal convention in the functional programming world that filter
> > means remove-if-not. But KEEP-IF is good to.
>
> Then an even better word than FILTER would be: DEMETER-IN-THE-FIELDS

Another example of the "thinking" that has made
DARPA CL the ugliest, clunkiest language that
the world has ever known.

WJ

unread,
Jan 24, 2013, 5:05:33 PM1/24/13
to
Racket:

> (filter (curry divisors? '(3 5)) (range 40))
'(0 15 30)

Bigloo:

(define-macro ($ . exprs) `(lambda (%) ,exprs))

(define (divisors? xs x)
(every ($ zero? (remainder x %)) xs))

(filter ($ divisors? '(3 5) %) (iota 40))
==> (0 15 30)

WJ

unread,
Dec 24, 2013, 3:35:37 PM12/24/13
to
Clojure:

(filter
(fn [n] (every? #(zero? (rem n %)) [3 5]))
(range 40))
===>
(0 15 30)
0 new messages