末尾再帰

末尾再帰をやってみる。

(defun my-fact (n)              ; 普通の再帰
  (if (= n 0) 1
    (* n (my-fact (1- n)))))(defun my-fact (n)              ; 末尾再帰
  (my-fact-loop n 1 1))

(defun my-fact-loop (n i p)
  (if (> i n) p
    (my-fact-loop n (1+ i) (* i p))))

;; test
(trace my-fact)
(trace my-fact-loop)

(my-fact 3)
 Calling (my-fact-loop 3 1 1)
  Calling (my-fact-loop 3 2 1)
   Calling (my-fact-loop 3 3 2)
    Calling (my-fact-loop 3 4 6)
    my-fact-loop returned 6       ; 一番奥で求めた値を持って帰るだけなので、
   my-fact-loop returned 6        ; ちゃんと末尾再帰になってる
  my-fact-loop returned 6
 my-fact-loop returned 6
6

うまくいっているようだが、やってることがさっぱりわからん。
末尾再帰になるように、補助関数を用意するのは分かる。
でもその引数をどうやって決めるのかとか、終了条件とかそのとき返す値の決め方がさっぱりだ。意味わからん。


なるべく再帰にしたいということは、なんとなく分かる。

再帰で書くと、ループで書いたものより、なにをやってるかがわかりやすいぞ
  ↓
じゃあ、再帰で書いてみよう
  ↓
とくに末尾再帰にすると、ループ処理に展開されるから早くなるし、スタック使わないからエレガントだ
  ↓
じゃあ、末尾再帰にしてみよう

という流れは分かるんだが・・・。

まあ、どうせ xyzzy には末尾再帰の最適化がないらしいので書けなくてもいいか。
と今は逃げておく。