题目要求我们给出这样一个 iterative-improve 函数:它接受一个用于检测猜测值是否足够好的函数(close-enough?),以及一个用于改进猜测值的函数(improve),并返回一个接受单个初始猜测值(first-guess)的过程,这个过程可以一直改进猜测值,直到猜测足够好。
根据描述,可以给出以下形式的函数:
(define (iterative-improve close-enough? improve)
(lambda (first-guess)
; ...
))
这个过程和 46 页的 fixed-point 非常的相似:
;;; p46-fixed-point.scm
(define tolerance 0.00001)
(define (fixed-point f first-guess)
(define (close-enough? v1 v2)
(< (abs (- v1 v2)) tolerance))
(define (try guess)
(let ((next (f guess)))
(if (close-enough? guess next)
next
(try next))))
(try first-guess))
fixed-point 函数不仅仅和 iterative-improve 非常相似,事实上, iterative-improve 就隐藏在 fixed-point 当中!
在 fixed-point 中, close-enough? 负责检查猜测是否足够好,而函数 f 负责改进猜测,如果我们将 close-enough? 函数抽取出来,成为额外的参数,那么 fixed-point 的定义就变成了:
(define (fixed-point f first-guess close-enough?)
(define (try guess)
(let ((next (f guess)))
(if (close-enough? guess next)
next
(try next))))
(try first-guess))
(define (close-enough? v1 v2)
(< (abs (- v1 v2)) tolerance))
(define tolerance 0.00001)
如果再将 first-guess 从 fixed-point 函数的参数列表中移走,变成另一个包裹 try 函数的 lambda 的参数, fixed-point 函数的定义就变成了这样:
(define (fixed-point f close-enough?)
(lambda (first-guess)
(define (try guess)
(let ((next (f guess)))
(if (close-enough? guess next)
next
(try next))))
(try first-guess)))
(define (close-enough? v1 v2)
(< (abs (- v1 v2)) tolerance))
(define tolerance 0.00001)
可以看到,现在的 first-point 定义已经和前面给出的 iterative-improve 形式一样了,如果将 fixed-point 函数改名成 iterative-improve ,将参数 f 改名成 improve ,并且删除 close-enough 函数和 dx 变量,题目要求的 iterative-improve 就(神奇地)显出庐山真面目了:
;;; 46-iterative-improve.scm
(define (iterative-improve close-enough? improve)
(lambda (first-guess)
(define (try guess)
(let ((next (improve guess)))
(if (close-enough? guess next)
next
(try next))))
(try first-guess)))
注意我们是如何一步步地从 fixed-point 函数中抽象出 iterative-improve 函数的,将这两个函数放在一起对比将是一个非常有趣的练习。
;;; 46-fixed-point.scm
(load "46-iterative-improve.scm")
(define (fixed-point f first-guess)
(define tolerance 0.00001)
(define (close-enough? v1 v2)
(< (abs (- v1 v2)) tolerance))
(define (improve guess)
(f guess))
((iterative-improve close-enough? improve) first-guess))
测试:
1 ]=> (load "46-fixed-point.scm")
;Loading "46-fixed-point.scm"...
; Loading "46-iterative-improve.scm"... done
;... done
;Value: fixed-point
1 ]=> (fixed-point cos 1.0)
;Value: .7390822985224024
;;; 46-sqrt.scm
(load "46-iterative-improve.scm")
(define (sqrt x)
(define dx 0.00001)
(define (close-enough? v1 v2)
(< (abs (- v1 v2)) dx))
(define (improve guess)
(average guess (/ x guess)))
(define (average x y)
(/ (+ x y) 2))
((iterative-improve close-enough? improve) 1.0))
测试:
1 ]=> (load "46-sqrt.scm")
;Loading "46-sqrt.scm"...
; Loading "46-iterative-improve.scm"... done
;... done
;Value: sqrt
1 ]=> (sqrt 9)
;Value: 3.