授業で久しぶりにschemeを触ったので、備忘録として。

授業ではscheme48って言うのを使ったんだけど、
ボクの知ってるschemeと若干処理系が違ったらしい。
first→car
rest→cdr
empty→nil, '()
ってなってた。

とりあえず、
末尾再帰関数に関して。
通常の再帰関数だと、

(define (list-sum list)
(cond ((null? list) 0)
(else (+ (car list) (list-sum (cdr list))))))

って書くよね。
これは、
(i)リストが空の時、0を返す。
(ii)それ以外のときは、リストの最初の数+ 残りのリストの合計値
再帰していく形なわけだ。

末尾再帰関数で書きなおすと、

(define (sum-iter list)
(define (calc sum list)
(cond
*1 (cdr list)))))
(calc 0 list))

となる。
これは、局所関数calcが
(i)リストが空の時、持っている合計値(sum)を返す。
(ii)それ以外のとき、再帰でcalcを呼び出す。このとき、sum= sum + リストの最初の値 list = 最初の値を除いた残りのリスト となる。
それで、sum-iterに与えられたリストに対して、sum=0でcalcを呼び出して、繰り返し処理をしているわけだ。

例 list = '(1 2 3 4) のとき。
1回目 sum = 0 , list='(1 2 3 4)
2回目 sum = 1 , list='(2 3 4)
3回目 sum = 3 , list='(3 4)
4回目 sum = 6 , list='(4)
5回目 sum = 10 list='()

普通の再帰関数と違うのは、戻り値での計算が無いこと。
普通の場合、 リストの最初の値+再帰関数の戻り値
ってなってるけど、
末尾再帰関数だと、最後は戻り値だけで返ってくるから早い。
その分のメモリを確保する必要が無いわけだ。
まぁ、高速化するときはこっちを使ったほうがいいんだっけ?

もう一つ、高階関数

授業でやったのはこんな感じだった

(define (double func)
(lambda (x) (func (func x))))

これを使って
((double add1) 0) #2
ってできたりする。
高階関数を使って、関数を返す関数を作ったわけですね。

いやー、それにしてもscheme面白いね・ω・

*1:null? list) sum) (else (calc (+ sum (car list