Я пытаюсь написать интерпретатор Scheme, но считаю, что 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 функции.
Что я хотел бы знать:
- Какие из этих функций будут переписаны ТШО и почему только эти?
- Существуют ли обстоятельства (например, 7), когда происходит перезапись совокупной стоимости владения, но функция по-прежнему потребляет память линейно?