SICP 全笔记

Exercise 1.43. If f is a numerical function and n is a positive integer, then we can form the nth repeated application of f, which is defined to be the function whose value at x is f(f(...(f(x))...)). For example, if f is the function x x + 1, then the nth repeated application of f is the function x x + n. If f is the operation of squaring a number, then the nth repeated application of f is the function that raises its argument to the 2nth power. Write a procedure that takes as inputs a procedure that computes f and a positive integer n and returns the procedure that computes the nth repeated application of f. Your procedure should be able to be used as follows:

((repeated square 2) 5)
625

Hint: You may find it convenient to use compose from exercise 1.42.

在不借用练习 1.42 的基础上,写递归 repeated 过程时需要保持清醒的头脑,告诉自己 repeated 过程是返回另外一个过程的,并且要考虑好终止条件是在 times = 0 还是 times = 1 的时候。迭代的 repeated 思路上比递归的要直接一些。当借用了练习 1.42 的 compose 的时候,写递归的 repeated 思路变得清晰很多,compose 作为一种粘合剂可以把 f 和 repeated 给粘合起来。

(define (repeated f times)
  (lambda (x)
    (cond ((= times 0) x)
          (else
           ((repeated f (- times 1))
            (f x))))))

(define (repeated/iter f times)
  (define (iter current-time result)
    (cond ((> current-time times) result)
          (else
           (iter (+ current-time 1) (f result)))))
  (lambda (x)
    (iter 1 x)))

; with compose as glue
(define (repeated/compose f times)
  (cond ((= times 0) (lambda (x) x))
        (else
         (lambda (x)
           (f ((repeated/compose f (- times 1)) x))))))

然后进行三个 repeated 过程的测试,注意测试 times = 0 的情况!


(assert= ((repeated square 0) 5) 5)
(assert= ((repeated/iter square 0) 5) 5)
(assert= ((repeated/compose square 0) 5) 5)

(assert= ((repeated square 1) 5) 25)
(assert= ((repeated/iter square 1) 5) 25)
(assert= ((repeated/compose square 1) 5) 25)

(assert= ((repeated square 2) 5) 625)
(assert= ((repeated square 2) 5)
         ((repeated/iter square 2) 5))
(assert= ((repeated/iter square 2) 5)
         ((repeated/compose square 2) 5))

(let ((v1-raise-power-to-2^n (lambda (n)
                            ((repeated/iter square n) 2)))
      (v2-raise-power-to-2^n (lambda (n)
                                    ((repeated square n) 2)))
      (v3-raise-power-to-2^n (lambda (n)
                                    ((repeated/compose square n) 2)))      )
  (assert= (v1-raise-power-to-2^n 4) (* 1024 64))
  (assert= (v2-raise-power-to-2^n 4) (* 1024 64))
  (assert= (v3-raise-power-to-2^n 4) (* 1024 64))  )

(let ((v1+n (lambda (n)
            (repeated (lambda (x) (+ x 1)) n)))
      (v2+n (lambda (n)
                    (repeated/iter (lambda (x) (+ x 1)) n)))
      (v3+n (lambda (n)
                    (repeated/compose (lambda (x) (+ x 1)) n))))
  (assert= ((v1+n 20) 1) 21)
  (assert= ((v2+n 20) 1) 21)
  (assert= ((v3+n 20) 1) 21))