末尾呼び出し最適化
いまさら末尾呼び出し最適化を見直しているのですが Gauche で以下のコードがスタックオーバーフローにならない理由が分からなくて混乱。
(define (my-map1 f l) (if (null? l) l (cons (f (car l)) (my-map1 f (cdr l))))) (my-map1 (lambda (x) x) (vector->list (make-vector 10000 3))) 0 LREF0 ; l 1 BNNULL 5 ; (null? l) 3 LREF0 ; l 4 RET 5 PRE-CALL(1) 11 7 LREF0 ; l 8 CAR-PUSH ; (car l) 9 LREF1 ; f 10 CALL(1) ; (f (car l)) 11 PUSH-PRE-CALL(2) 18 13 LREF1-PUSH ; f 14 LREF0 ; l 15 CDR-PUSH ; (cdr l) 16 GREF-CALL(2) #<identifier user#my-map1>; (my-map1 f (cdr l)) 18 PUSH-GREF-TAIL-CALL(2) #<identifier user#kons>; (kons (f (car l)) (my-map1 f (cdr l))) 20 RET
my-map1 の再帰のたびに (f (car l)) の結果と frame などがスタックにたまる気がするのだけど。何か大切な事を見落としている予感。