An operator section is a procedure that is derived from another
procedure by ``filling in'' some but not all of its arguments. For
instance, the double procedure defined by
(define double
(lambda (n)
(* 2 n)))
qualifies as an operator section, since it fills in the first argument to
the * procedure with the particular value 2. Operator
sections are often used as arguments to higher-order procedures such as
list-of, tallier, and generate-list
from the first lab on procedures as
values.
For instance, we could construct a procedure that counts the number of
occurrences of the symbol 'n/a (``not available'') in a given
list as (tallier (lambda (whatever) (eq? 'n/a whatever))).
Here the value of the lambda-expression is an operator section
of eq?, with the first argument filled in with the particular
value 'n/a.
We can even define higher-order procedures to construct operator sections
for us. Such procedures are not primitives, but they are easily defined --
I'll use the name left-section for a higher-order procedure
that takes a procedure of two arguments and a value to drop in as its first
argument, and returns the relevant operator section:
(define left-section
(lambda (procedure filler-in)
(lambda (expected)
(procedure filler-in expected))))
So we could define double as (left-section * 2)
and (lambda (whatever) (eq? 'n/a whatever)) as
(left-section eq? 'n/a).
Define and test the analogous higher-order procedure
right-section, which takes a procedure of two arguments and a
value to drop in as its second argument, and returns the operator
section that expects the first argument. (For instance,
(right-section expt 3) is a procedure that computes the cube
of any number it is given.)
Using the generate-list procedure from the first lab on procedures as values and an
operator section, define a procedure powers-of-two that
constructs and returns a list of powers of two, in ascending order, given
the length of the desired list:
> (powers-of-two 7) (1 2 4 8 16 32 64)
Define a procedure bounded-mu that takes two arguments, a
predicate pred and a natural number limit, and
returns the least natural number less than limit that
satisfies pred, or #f if there is no such number.
Use bounded-mu to find the least natural number less than 1000
that leaves a remainder of 5 when divided by 7, a remainder of 7 when
divided by 11, and a remainder of 11 when divided by 13.
To filter a list is to examine each of its elements in turn, retaining some for a new list while eliminating others. For instance, given a list of integers, the following procedure filters it to remove the negative ones:
(define remove-negatives
(lambda (ls)
(cond ((null? ls) null)
((negative? (car ls)) (remove-negatives (cdr ls)))
(else (cons (car ls) (remove-negatives (cdr ls)))))))
We could write similar procedures to remove the whitespace characters from
a list of characters, or to exclude any occurrences of the symbol
'n/a from a list:
(define remove-whitespace
(lambda (ls)
(cond ((null? ls) null)
((char-whitespace? (car ls)) (remove-whitespace (cdr ls)))
(else (cons (car ls) (remove-whitespace (cdr ls)))))))
(define remove-n/a-symbols
(lambda (ls)
(cond ((null? ls) null)
((eq? 'n/a (car ls)) (remove-n/a-symbols (cdr ls)))
(else (cons (car ls) (remove-n/a-symbols (cdr ls)))))))
Similar filtering procedures occur so frequently that it's useful to have a higher-order procedure to construct them. Using the method described in the first lab on procedures as values, we can easily define such a procedure:
(define remove
(lambda (predicate)
(letrec ((recurrer (lambda (ls)
(cond ((null? ls) null)
((predicate (car ls)) (recurrer (cdr ls)))
(else (cons (car ls) (recurrer (cdr ls))))))))
recurrer)))
(define remove-negatives (remove negative?))
(define remove-whitespace (remove char-whitespace?))
(define remove-n/a-symbols (remove (left-section eq? 'n/a)))
Here is an interesting list of natural numbers:
(define duplicated-membership-numbers (list 1471 4270))
Define a Scheme procedure remove-multiple-voters that takes a
list of non-empty lists as its argument and filters out of it the lists in
which the first element is also an element of
duplicated-membership-numbers.
Define the intersection procedure (from the lab on local binding and
recursion) using remove and right-section.
The filters constructed by remove are designed to
exclude list elements that satisfy a given predicate. Define a
higher-order procedure filter that returns a filtering
procedure that retains the elements that satisfy a given predicate
(excluding those that fail to satisfy it). For instance, applying
the filter (filter even?) to a list of integers should return
a list consisting of just the even elements of the given list.
This document is available on the World Wide Web as
http://www.cs.grinnell.edu/~stone/courses/scheme/procedures-as-values-continued.xhtml
created October 30, 1997
last revised March 17, 2000