我正在尝试编写一个 Scheme 解释器,但发现 TCO 难以实现。我不确定函数必须具备哪些属性才能使 TCO 发挥作用。
1) 在定义结尾处带有自递归调用的函数:
(define (sum-list list accum)
(if (null list) accum
(sum-list (cdr list) (+ accum 1))))
2) 具有不在定义末尾的自递归调用的函数:
(define (sum-list list accum)
(cond ((not (null list))
(sum-list (cdr list) (+ accum 1)))
(else accum)))
3) 在返回之前将递归调用存储在变量中的函数:
(define (sum-list list accum)
(let ((sum
(if (null list)
accum
(sum-list (cdr list (+ accum 1))))))
sum))
4) 相互递归函数:
(define (sum-list list accum)
(if (null list)
accum
(other-function (cdr list) (+ accum 1))))
(define (other-function list accum)
(sum-list list accum))
5) 在函数定义的末尾简单地调用另一个不相关的函数:
(define (foo)
(bar))
6)我能想到的最棘手的情况是闭包。如果我坚持对范围内变量的引用怎么办?
(define (sum-list list accum ignored)
(let ((local-var 12345))
(if (null list)
accum
(sum-list
(cdr list)
(+ accum 1)
(lambda () local-var)))))
7) 在函数定义的末尾调用另一个函数,以自递归调用作为参数:
(define (sum-list list)
(if (null list)
0
(+ 1 (sum-list (cdr list)))))
据我了解,TCO 实现(在 Scheme 和 Common Lisp 中)重写了对 TCO 友好的函数,因此它们必须能够静态检测对 TCO 友好的函数。
我想知道的是:
- TCO 会重写哪些函数,为什么只重写这些函数?
- 是否发生 TCO 重写但函数仍线性消耗内存的情况(例如 7)?