Map and filter usually have only one arg and if they have 2, the 2nd is almost always a 0-based index. They look identical in most languages, even when Microsoft chooses to call them Select and Where.
Reduce has an accumulator and a 2-arg function and languages are not very consistent amongst each other as to whether it's reduce(initial_acc, callback(acc, elem)) or reduce(callback(acc, elem), initial_acc) or reduce(callback(elem, acc), initial_acc) or what.
Hard to remember. Also some languages have a version of reduce that doesn't take an initial accumulator at all, which is just a footgun waiting for you to hit an empty collection. Also ALSO, the accumulator can easily become awkward in languages that don't support anonymous types or don't support easy mutation of an anonymous type record. Which is most of them!
While map is a great name, I always struggle to remember if ‘filter’ keeps elements that match the condition or removes them.
I mean, it’s like a colander: you filter noodles and water, but which one do you keep? The noodles, right? But, replace noodles with tea and now you want to keep the water part.
`remove-if-not` was deprecated before the Common Lisp standard was approved and yet it remained (and will never be removed because the standard will never be updated). That's not deprecated for any practical purpose. And it's more convenient than using `(remove-if (complement #'some-predicate) sequence)`
Scheme has `filter` and `filter-not` in the SRFI-1 list library. Both of which can easily be written using a fold to bring this vaguely on topic.
Nope! Common Lisp's filter is in fact remove-if-not, which is exactly the same thing as "keep if": keep all items which match the predicate (removing those that do not).
I suspect the reason the function was deprecated was its naming, nothing more; had it been called retain-if or keep-if, it would not have attracted deprecating attention.
The smell added to your code is just the double-negative name of that function, not what it's doing for you.
The name filter smells even more. Is that filtering for items that match? Or filtering out?
In physical filters, sometimes the filtrate is considered the payload output (that which passes through the filter) and sometimes the retentate (that which is caught in the filter).
I agree that keep-if is a better name. But you reiterated my point: remove-if works in the counterintuitive way the original comment noted, i.e. not like the common connotation of 'filter.'
As for deprecation, IIRC the '-if-not' functions were deprecated because the committee felt the 'complement' function accomplished that task better.
Edit: My IIRC seems largely correct. More detail at
Nonetheless, they were fooled by that function, because it's just keep-if by a funny name that includes "not" suggesting that it contains a complement that might be factored out.
If you want keep-if, you don't want to use a different function, which forces you to complement your predicate. If you want (keep-if #'redp jellybean-list) to keep the red jelly beans, you don't want to write (remove-if (complement #'not-red-p) jellybean-list). If keep-if has a silly name remoe-if-not, you might nonetheless prefer (remove-if-not #'redp jelly-bean-list).
Shims like complements are ugly, and compilers won't optimize through them for arbitrary function definitions (whose source code is not even in scope), so it is good to have both keepers and removers. Heck, it's useful to have a function which does both in one pass returning two values: the filtrate and the retentate.
rspeele · · focus · HN ↗
Reduce has an accumulator and a 2-arg function and languages are not very consistent amongst each other as to whether it's reduce(initial_acc, callback(acc, elem)) or reduce(callback(acc, elem), initial_acc) or reduce(callback(elem, acc), initial_acc) or what.
Hard to remember. Also some languages have a version of reduce that doesn't take an initial accumulator at all, which is just a footgun waiting for you to hit an empty collection. Also ALSO, the accumulator can easily become awkward in languages that don't support anonymous types or don't support easy mutation of an anonymous type record. Which is most of them!
jiehong · · focus · HN ↗
While map is a great name, I always struggle to remember if ‘filter’ keeps elements that match the condition or removes them.
I mean, it’s like a colander: you filter noodles and water, but which one do you keep? The noodles, right? But, replace noodles with tea and now you want to keep the water part.
Naming is hard I guess.
seanw444 · · focus · HN ↗
dreamcompiler · · focus · HN ↗
(It also has remove-if-not but that's deprecated and if you use it your code smells.)
shawn_w · · focus · HN ↗
Scheme has `filter` and `filter-not` in the SRFI-1 list library. Both of which can easily be written using a fold to bring this vaguely on topic.
kazinator · · focus · HN ↗
I suspect the reason the function was deprecated was its naming, nothing more; had it been called retain-if or keep-if, it would not have attracted deprecating attention.
The smell added to your code is just the double-negative name of that function, not what it's doing for you.
The name filter smells even more. Is that filtering for items that match? Or filtering out?
In physical filters, sometimes the filtrate is considered the payload output (that which passes through the filter) and sometimes the retentate (that which is caught in the filter).
keep-if is readable.
dreamcompiler · · focus · HN ↗
As for deprecation, IIRC the '-if-not' functions were deprecated because the committee felt the 'complement' function accomplished that task better.
Edit: My IIRC seems largely correct. More detail at
<a href="https://www.lispworks.com/documentation/HyperSpec/Issues/iss345_w.htm" rel="nofollow">https://www.lispworks.com/documentation/HyperSpec/Issues/iss...
kazinator · · focus · HN ↗
If you want keep-if, you don't want to use a different function, which forces you to complement your predicate. If you want (keep-if #'redp jellybean-list) to keep the red jelly beans, you don't want to write (remove-if (complement #'not-red-p) jellybean-list). If keep-if has a silly name remoe-if-not, you might nonetheless prefer (remove-if-not #'redp jelly-bean-list).
Shims like complements are ugly, and compilers won't optimize through them for arbitrary function definitions (whose source code is not even in scope), so it is good to have both keepers and removers. Heck, it's useful to have a function which does both in one pass returning two values: the filtrate and the retentate.