Exercise 1.33. You can obtain an even more general version of accumulate (exercise 1.32) by introducing the notion of a filter on the terms to be combined. That is, combine only those terms derived from values in the range that satisfy a specified condition. The resulting filtered-accumulate abstraction takes the same arguments as accumulate, together with an additional predicate of one argument that specifies the filter. Write filtered-accumulate as a procedure. Show how to express the following using filtered-accumulate:
a. the sum of the squares of the prime numbers in the interval a to b (assuming that you have a prime? predicate already written)
b. the product of all the positive integers less than n that are relatively prime to n (i.e., all positive integers i < n such that GCD(i,n) = 1).
我们已经知道 accumulate 能够顺序从 a 到 b 进行处理。filtered-accumulate 的特点在于,在处理 a 到 b 的序列的时候,我们能够剔除掉不满足我们条件的数字,所以很容易想到两个过程的差别在于 filtered-accumulate 对于序列中的一个数字 x,我们要首先去判断这个 x 是不是满足我们条件的数字,如果满足条件才去进行 combiner 的步骤
(define (filtered-accumulate combiner null-value term a next b p)
(cond ((> a b) null-value)
((not (p a))
(filtered-accumulate combiner null-value term (next a) next b p))
(else
(combiner (term a)
(filtered-accumulate combiner null-value term (next a) next b p)))))
使用这个过程,我们可以来定义 a 和 b 题目中要求的过程了。现在只需要对各种条件一一入座就行:
(load "prime.scm")
(define (sum-of-square-of-prime a b)
(define (inc x) (+ x 1))
(filtered-accumulate + 0 square a inc b prime?))
(define (product-of-positive-and-prime n)
(define (identity x) x)
(define (inc x) (+ 1 x))
(define (gcd a b)
(if (= b 0)
a
(gcd b (remainder a b))))
(define (relative-prime-to-n? x)
(= (gcd x n) 1))
(filtered-accumulate * 1 identity 1 inc n relative-prime-to-n?))
最后我们来进行测试:
(load "../testframe.scm")
(assert= (sum-of-square-of-prime 1 10)
(+ (* 2 2) (* 3 3) (* 5 5) (* 7 7)))
(assert= (product-of-positive-and-prime 10)
(* 3 7 9))
(assert= (product-of-positive-and-prime 11)
(* 1 2 3 4 5 6 7 8 9 10))