Skip to content

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 
;     are relatively prime to n (i.e., all positive integers 
;     i < n such that GCD(i,n) = 1).

; -----------------------------------
; Answer
; -----------------------------------
; Let's define `filtered-accumulate` function

(define (filtered-accumulate combiner null-value filter term a next b)
    (if (> a b) null-value
        (if (filter a)
            (combiner (term a) 
                      (filtered-accumulate combiner null-value filter term (next a) next b))
            (combiner null-value 
                      (filtered-accumulate combiner null-value filter term (next a) next b)))))

; (a) Let's test with `prime?` procedure
(define (prime? n)
    (define (divides? a b) (= (remainder b a) 0))
    (define (smallest-divisor n) (find-divisor n 2))
    (define (find-divisor n test-divisor)
        (cond ((> (square test-divisor) n) n)
              ((divides? test-divisor n) test-divisor)
              (else (find-divisor n (+ test-divisor 1)))))
    (if (= n 1) #f
        (= n (smallest-divisor n)))
)
(define (inc x) (+ x 1))
(define (sum-of-squares-prime a b)
    (filtered-accumulate + 0 prime? square a inc b))

(sum-of-squares-prime 1 10) ;Value: 87 (2^2 + 3^2 + 5^2 + 7^2)

; (b) Define `relatively-prime?` filter
(define (gcd a b) 
    (cond ((< a b) (gcd b a)) 
          ((= b 0) a) 
          (else (gcd b (remainder a b))))) 

(define (relatively-prime? a b)
    (= (gcd a b) 1))
(define (product-of-relative-prime-nums n)
    (define (filter x) (relatively-prime? x n))
    (define (f x) x)
    (filtered-accumulate * 1 filter f 1 inc n)
)
(product-of-relative-prime-nums 10) ;Value: 189