文責: | @iriya_ufo |
---|
以下の3つの手続きを考える.
;; a から b までの整数の和
(define (sum-integers a b)
(if (> a b)
0
(+ a (sum-integers (+ a 1) b))))
;; 与えられた範囲の整数の三乗の和
(define (sum-cubes a b)
(if (> a b)
0
(+ (cube a) (sum-cubes (+ a 1) b))))
;; 級数の項の並びの和
(define (pi-sum a b)
(if (> a b)
0
(+ (/ 1.0 (* a (+ a 2))) (pi-sum (+ a 4) b))))
上記の級数は次のようなものである.
\(\frac{1}{1*3} + \frac{1}{5*7} + \frac{1}{9*11} + ...\)
以上3つの手続きは共通の基本パターンを持っているのでひな形を作る事ができる.
(define (<name> a b)
(if (> a b)
0
(+ (<term> a)
(<name> (<next> a) b))))
このような共通のパターンが見つかった場合, 有用な抽象化があることを意味する. プログラムの設計者として, 特定の和を表現する手続きではなく, 総和自身の概念を表現する手続きが書きたい. 以下のように書くことができる.
(define (sum term a next b)
(if (> a b)
0
(+ (term a)
(sum term (next a) next b))))
sum は引数として下限 a と上限 b を取り, 手続き term と next を取る.
これを使って最初に提示した3つの手続きを, それぞれ抽象化することができる.
;; a から b までの整数の和
(define (identity x) x)
(define (sum-integers a b)
(sum identity a inc b))
(sum-integers 1 10) ;; => 55
;; 与えられた範囲の整数の三乗の和
(define (inc n) (+ n 1))
(define (sum-cubes a b)
(sum cube a inc b))
(sum-cubes 1 10) ;; => 3025
;; 級数の項の並びの和
(define (pi-sum a b)
(define (pi-term x)
(/ 1.0 (* x (+ x 2))))
(define (pi-next x)
(+ x 4))
(sum pi-term a pi-next b))
(* 8 (pi-sum 1 1000)) ;; => 3.139592655589783
抽象化された sum ができると, 更なる概念を作るための部品とすることができる.
例えば (a, b) 間の関数 f の定積分は数値的には式
と表される. これを手続きとして表現できる.
(define (integral f a b dx)
(define (add-dx x) (+ x dx))
(* (sum f (+ a (/ dx 2.0)) add-dx b)
dx))
(integral cube 0 1 0.01) ;; => .24998750000000042
(integral cube 0 1 0.001) ;; => .249999875000001