我正在用 JavaScript 制作一个玩具 Lisp 解释器。JS 没有尾递归消除(TRE),所以我在 JS(伪代码)中使用 while 循环实现了 TRE:
function eval (exp, env)
while true
if exp is self evaluating
return exp
else if ...
...
else if exp is a function call
procedure = eval(car(exp), env)
arguments = eval_operands(cdr(exp), env)
exp = procedure.body
env = extend_env(procedure.env, env)
continue # tail call
所以我很高兴,像下面这样的尾递归函数不会用完堆栈:
(define +
(lambda (n m)
(cond ((zero? n) m)
(else (+ (sub1 n) (add1 m))))))
(+ 10000 1) ;=> 10001
但是,不是尾递归的函数会耗尽 JS 堆栈(因为 JS 代码在 上重复太多eval_operands
):
(define +
(lambda (n m)
(cond ((zero? n) m)
(else (add1 (+ (sub1 n) m))))) ; not proper tail-recursive
(+ 10000 1) ;=> JS: Maximum call stack size exceeded
如何处理非尾递归函数?有什么选择?什么是好的资源?我读过一些关于蹦床、堆栈外部化和延续传递风格的文章,但我能找到的只是如何以这些风格编写代码,而不是如何使用这些技术来编写解释器。