1.2.1 Linear Recursion and Iteration
n!でいろいろみてみよう
置き換えモデルだと山型のスタック
見方を変えてみよう.
これまでの計算結果を保持してみると...
(define (factorial n) (fact-iter (1 1 n)) (definie (fact-iter product counter max-count) (if (> counter max-count) product (fact-iter (* product counter) (+ counter 1) (max-count))))
とすると、展開してもただのループになるので、記憶しておく量がすくなくて済む.
比較
- 置き換えモデルは山形に展開、収縮する
- 2つめのやつは収縮/膨張しない
- プログラム側で実行経過を保持
- 反復プロセスという名前
- 状態変数を保持している
- 実行に伴い状態変数が変化していき、これがトリガとなって実行が終了
- 状態数nに比例する場合「線形反復プロセス」という
もっと違う見方で比較
- 反復プロセス
- 全てのポイントでプロセスの状態をプログラム側で保持
- プログラムが途中でとまったらとしたら、保持している値を代入してあげればそこから再実行可能
- 再帰プロセス
- インタプリタが保持している隠れパラメータを復元する必要アリ
- 遅延が長くなればなるほど保持すべき情報は大きくなる
注意
混乱の原因
- Cなどの実装では、反復プロセスでも再帰プロセスでも関数が実行されるとメモリを食う(ホント?)
- 反復プロセスはループ構文を使ってのみ表現可能
Exercise 1.9
(define (+ a b) (if (= a 0) b (inc (+ (dec a) b)))) (+ 4 5) (inc (+ 3 5)) (inc (inc (+ 2 5)) (inc (inc (inc (+ 1 5))) (inc (inc (inc (inc (+ 0 5))))) (inc (inc (inc (inc (5))))) (inc (inc (inc (6)))) (inc (inc (7))) (inc (8)) (9) 9 (define (+ a b) (if (= a 0) b (+ (dec a) (inc b)))) (+ 4 5) (+ 3 6) (+ 2 7) (+ 1 8) (+ 0 9) 9
Excersice 1.10
gosh> (define (A x y) (cond ((= y 0) 0) ((= x 0) (* 2 y)) ((= y 1) 2) (else (A (- x 1) (A x (- y 1)))))) A gosh> (A 1 10) 1024 gosh> (A 2 4) 65536 gosh> (A 3 3) 65536 (define (f n) (A 0 n)) => f(n) = 2n (define (g n) (A 1 n)) => g(n) = (define (A x y) (cond ((= y 0) 0) ((= x 0) (* 2 y)) ((= y 1) 2) (else (A (- x 1) (A x (- y 1)))))) (A 1 3) (A 0 (A 1 2)) (A 0 (A 0 (A 1 1))) (A 0 (A 0 (2))) (A 0 (4)) (8) 8 2^n (define (h n) (A 2 n)) (define (A x y) (cond ((= y 0) 0) ((= x 0) (* 2 y)) ((= y 1) 2) (else (A (- x 1) (A x (- y 1)))))) gosh> (h 1) 2 gosh> (h 2) 4 gosh> (h 3) 16 gosh> (h 4) 65536 (2n)^2n