SICPラン③(p26~1.18. 例: ブラックボックス抽象化としての手続き)

 作られた手続きは、中身が詳細に知られる必要がない。簡単な例だとニュートン法で用いたsquareで、返り値として引数の二乗がかえってこれば良いのであって、どのように実装されているのかは知る必要がない。ブラックボックスで構わないのである。

そして、一連の手続きのネストを作ると、その他の手続きにおいても同じ名前で使うことができる。(つまりある数の平方根を求める手続き以外でも、improveやgood-enough?などが利用できるようになる。sqrt以外の手続き、いわゆるサブ手続きをsqrt内に局所化することで実現する。これをブロック構造という*1。)

(define (sqrt x)
  (define (good-enough? guess x)
    (< (abs (- (square guess) x)) 0.001))
  (define (improve guess x) (average guess (/ x guess)))
  (define (sqrt-iter guess x)
    (if (good-enough? guess x)
        guess
        (sqrt-iter (improve guess x) x)))
  (sqrt-iter 1.0 x))

そしてさらにsqrt内で変数xを自由変数として扱うと、そのスコープ内における各手続きに明示的に値を渡す必要がなくなる。

(define (sqrt x)
  (define (good-enough? guess)
    (< (abs (- (square guess) x)) 0.001))
  (define (improve guess) (average guess (/ x guess)))
  (define (sqrt-iter guess)
    (if (good-enough? guess)
        guess
        (sqrt-iter (improve guess))))
  (sqrt-iter 1.0))

xの値の探索は、その手続きが定義されている手続きの環境内で探索される。その範囲をレキシカルスコーピング(lexical scoping)という。(第三章で詳しく扱う)
 

*1:ちなみに、ブロック構造はAlgol 60という数値計算用の構造化言語から生まれた概念であるらしい。1958年にIFIP(International Federation for Infomation Processing)がAlgolを開発し、1960年にAlgol 60の仕様が策定された。実用というよりも、論文などにおいてのロジック記述に多用されているようである