《計算機程序的構造和解釋》思考筆記1:如何抽象

;下面的問題是,我們之前是通過不斷猜測點來找到一個數的平方根的。現在我們學了不定點fixed-point,我們可以讓它來找平方根,其實就是x^2=y,x=y/x,轉化成求f(x)=y/x這個函數的不動點。怎麼做呢?
;先寫好fixed-point函數:
(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))


;然後我們可以這樣定義:
(define (sqrt1 x)
  (fixed-point (lambda (y)
                 (/ x y))
               1.0))
;但是這樣寫有問題,y,和x/y一直在那循環,振盪。所以寫一個y=(1/2)(y+x/y),這樣就不會出現振盪了。
;下面寫一個函數,它接受一個函數f,然後
(define (average-damp f)
  (lambda (x)
    (average x
             (f x))))
(define (average x y) (/ (+ x y) 2))
;我們重新來定義這個sqrt:
(define (sqrt2 x)
  (fixed-point (average-damp (lambda (y)
                 (/ x y)))
               1.0))
  
;我們把上面寫得再簡單點,好讀點:
(define (sqrt3 x)
  (let ((lam (lambda (y)
                 (/ x y))))
  (fixed-point (average-damp lam)
               1.0)))

;下面我們用牛頓法:其實就是類似於上面的average-damp.首先,我們要求導:

; 給定一個函數g,讓它返回一個過程,這個過程是這個函數g的導數:
(define (deriv g)
  (lambda (x)
    (/ (- (g (+ x dx)) (g x))
       dx)))
(define dx 0.00001)
;下面這個函數也返回一個過程,它接受g函數,也返回一個函數
(define (newton-transform g)
  (lambda (x)
  (- x
     (/ (g x)
        ((deriv g) x)))))
;現在用這個牛頓法來定義sqrt;
(define (sqrt4 x)
  (fixed-point (newton-transform (lambda (y) (/ x y))) 1.0))
;牛頓法:
(define (newton-method g guess)
  (fixed-point (newton-transform g) guess))
;平均阻尼法
(define (average-method g guess)
  (fixed-point (average-damp g) guess))

(define (sqrt5 x)
   (let ((lam (lambda (y)
                 (- (square y) x))))
  (fixed-point (newton-transform lam) 1.0)))

(define (square x) (* x x))

;筆記:這裏總結一下,最抽象的其實是fixed-point,它基本上可以求任何函數的不動點。然後這個newton法,還有前面的平均阻尼法,它們都是一種特殊形式,它們規定了怎麼變換函數g,而sqrt又是一種更特殊的,它規定
;g是什麼?你想通過阻尼,還是通過牛頓法,那是你自己的選擇。

;我們能不能進一步抽象呢?
;我發現,newton-method 和之前的average-method方法,它們大多是共同的;
(define (fixed-point-of-transform g guess transform)
  (fixed-point (transform g) guess))

;上面這個方法就更抽象了,你可以自定義transform,也可以自定義g,這是一個更抽象,更具一般性的函數。

;用上面的函數,我們來定義sqrt:
(define (sqrt x)
  (let ((g (lambda (y) (average y (/ x y))))))
  (fixed-point-of-transform g 1.0 newton-transform))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章