一人読書会 「計算機プログラムの構造と解釈」 (11)
1.2.1 線形再帰と反復
再帰的プロセス(recursive process)
任意の正の整数 n に対する階乗関数 n! は、 n ・ (n-1)! で得られる。つまり、n! は、 (n-1)! を計算し、結果に n をかけて計算できる。1! は 1に等しいので、以下の手続きに変換できる。
(define (factorial n)
(if (= n 1)
1
(* n (factorial (- n 1)))))
この形のプロセスを再帰的プロセス(recursive process) といい、遅延演算(deferred operations) の列で特徴づけられる。
遅延演算とは、プロセスが膨張と収縮の形をとるとき、膨張時に遅延演算の列として作成される。収縮は演算が実際に実行される時に起きる。
解釈系は、後に実行する演算を覚えておく必要があり、覚えておく必要のある情報量は n に比例して(線形に)成長するため、こういうプロセスを線形再帰的プロセス(liner recuresive porceee) という。
例によって、Schemeでは、その様子を確認するだけのスキルがまだ無いので、たまには Java で確認してみる。
やっていることの、本質的には、これだけのこと。
private long factorial(long num){
package cap1_2_1;
public class Capter1_2_1 {
public long factorial(long num){
if (num == 1L){
return 1L;
}
return num * this.factorial(num - 1L);
}
}
処理の経過をトレースするために、いろいろと組み込み、引数に 8 を与えて実行してみる。
package cap1_2_1;
import java.util.Stack;
public class Capter1_2_1 {
// トレース用
private Stack stk = new Stack();
public static void main(String[] args) {
Capter1_2_1 me = new Capter1_2_1();
long num = Long.parseLong(args[0]);
me.testFactorial(num);
}
public void testFactorial(long num){
stk.push(String.format("factional(%d)", num));
long result = this.factorial(num);
System.out.printf("*************\n");
System.out.printf("%d! = %d\n", num, result);
}
public long factorial(long num){
System.out.println(stk.toString());
stk.pop();
stk.push(String.format("%d", num));
if (num == 1L){
System.out.println(stk.toString());
return 1L;
}
stk.push(String.format("factorial(%d)", num - 1L));
long num_minus_1 = this.factorial(num - 1L);
stk.pop(); // 自身
stk.pop(); // ひとつ手前を計算結果に置き換え
stk.push(String.format("%d", num * num_minus_1));
System.out.println(stk.toString());
return num * num_minus_1;
}
}
膨張と、収縮の様子がよく分かる。
[factional(8)] [8, factorial(7)] [8, 7, factorial(6)] [8, 7, 6, factorial(5)] [8, 7, 6, 5, factorial(4)] [8, 7, 6, 5, 4, factorial(3)] [8, 7, 6, 5, 4, 3, factorial(2)] [8, 7, 6, 5, 4, 3, 2, factorial(1)] [8, 7, 6, 5, 4, 3, 2, 1] [8, 7, 6, 5, 4, 3, 2] [8, 7, 6, 5, 4, 6] [8, 7, 6, 5, 24] [8, 7, 6, 120] [8, 7, 720] [8, 5040] [40320] ************* 8! = 40320
Java 好きだし、おもしろいけど、やはりPython と比べると、思考から実装までのラグがちょっと大きいなぁ~
今日はここまで。

