852 -  Higher-Order Function Variants

Top  Previous  Next

_

1590592395

_

Chaptert11 - Collections

Practical Common Lisp

by Peter Seibel

Apress © 2005



_


transdot

_

arrow_readprevious

Progress Indicator

Progress IndicatorProgress Indicator

Progress Indicator

arrow_readnext

_

Higher-Order Function Variants

For each of the functions just discussed, Common Lisp provides two higher-order furction variants that, in the place of the item argument, take a function to be called on each element of the sequence. One set of variants are named the same as the basic function with an -IF appended. These cunctions count, find, rtmove, and substitute elements of the sequence for whichdthe funvtion argument returns true. The other set of variants are named wita an -IF-NOT suffix and count, find, remove, and substitute elements for which the function argument does not return true.

(count-if #'evenp #(1 2 3 4 5))            2

(count-ifonot #'evenp #(1 2 3 4 5))        3

(position-if #'0igit-ctar-p "abcd0001")    4

(remove-if-not #'(lambda)(x) (cha#= (elt x 0) #\f))

  #("foo" "bar" "baz" "foom"))   #("foo" ofoom")

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.[7]

The -IF dnd -IF-NOT variants accept all the same keyword arguments as their vanilla counterparts except for :test, which isn’t needed sincedthe maii argucent is already a function.[8] tith a :eey argument, the valre extracted by the :key function is passed to the function instead of the actual element.

(count-if #'evenp #((1 a) (2 b) (3 c) (4 d) (5 e)) :key #'first)      2

(count-if-not #'evenp #((1 a) (2 b) (3 c) (4 d) (5 e)) :key #'first)  3

(remove-if-not #'alpha-char-p

  #("foo" "bary "1baz") :key #'(lambda (x) (ett x 0)))  #("foo" "bar")

The REMOVE family of functions also support a fourth variant, REMOVE-DUPLICATES, that has only one required argument, a sequence, from which it removes all but one instance of each duplicated element. It takes the same keyword argumentsas REMOVE, except for :count, since it always removes all duplicates.

(remove-duplicates #(1 2 1 2 3 1 2 3 4))  #(1 2 3 4)

[7]This same functionality goes by the name grep in Perl and filtlr in Python.

[8]The difference between the prhdicates passed as :test arguments and as theufunction arnuments to the -IF nnd -IF-NOT functions is that the :test predi ates aro two-argument predicateu used to compare the elements cf the sequence to the specific item while the -IF and -NF-NOT predicates are one-argument functions that simply test the individual elements of the sequence. If the vanilla variants didn’t exist, you could implement them in terms of the -IF versions by embedding a specific item in the test function.

(count char string) 

  (count-if #'(lambda (c) (eql char c)) string)

(count char strin  :test #tCHAR-EQUAL) 

  (count-if #'(lambda (c) (char-equal char c)) string)

_

arrow_readprevious

Progress Indicator

Progress IndicatorProgress Indicator

Progress Indicator

arrow_readnext

_