Problem: Given a collection of values and a predicate (of arity 1) that any of the values might or might not satisfy, determine the number of values that do in fact satisfy the predicate.
We'll assume that the values are collected in a list. Here are three divergent approaches that indicate something about the range of programming styles in Scheme.
The first is a classical recursion in which successive instances of the
same problem differ with respect to two parameters: rest
,
the value of which is the part of the list containing the elements that
have not yet been examined, and tally
, the value of which is
the number of elements, among those that have already been examined, that
satisfy the predicate.
The advantage of carrying tally
along as a parameter is that
the recursive call becomes a ``tail'' recursion (one in which the value of
returned from a call is forwarded without further computation to the next
caller down). An implementation of Scheme is required to optimize
tail-recursive calls.
The ``named let'' construction provides a convenient way to define and
invoke the local recursive procedure, loop
, with appropriate
initial values for the parameters.
The second version exploits Scheme's support for a functional programming style. The idea is to define a mapping (here called(define selective-tally (lambda (values predicate) (let loop ((rest values) (tally 0)) (if (null? rest) tally (loop (cdr rest) (if (predicate (car rest)) (+ tally 1) tally))))))
weight
)
that takes every value that satisfies the predicate to 1 and every value
that does not satisfy the predicate to 0. One then uses Scheme's
map
procedure to obtain the image of the list of values under
that mapping, and applies the +
procedure to the resulting
list to obtain its sum.
The third version is written in the procedural style, with explicit iteration and assignment.(define selective-tally (lambda (values predicate) (let ((weight (lambda (object) (if (predicate object) 1 0)))) (apply + (map weight values)))))
(define selective-tally (lambda (values predicate) (do ((rest values (cdr rest)) (tally 0)) ((null? rest) tally) (if (predicate (car rest)) (set! tally (+ tally 1))))))
This document is available on the World Wide Web as
http://www.math.grin.edu/~stone/events/scheme-workshop/tallying.html