Scheme中的递归函数是否总是尾部调用优化?

Scheme中的递归函数是否总是尾部调用优化?,scheme,tail-call-optimization,Scheme,Tail Call Optimization,我在Scheme中读过一些关于尾部调用优化的内容。但我不确定我是否理解尾部调用的概念。如果我有这样的代码: (define (fac n) (if (= n 0) 1 (* n (fac (- n 1))))) (define (factorial n) (let fact ([i n] [acc 1]) (if (zero? i) acc (fact (- i 1) (* acc i))))) 是否可以

我在Scheme中读过一些关于尾部调用优化的内容。但我不确定我是否理解尾部调用的概念。如果我有这样的代码:

(define (fac n)
  (if (= n 0)
      1
      (* n (fac (- n 1)))))
(define (factorial n)
    (let fact ([i n] [acc 1])
      (if (zero? i)
          acc
          (fact (- i 1) (* acc i)))))
是否可以对其进行优化,使其不会占用堆栈内存? 或者尾部调用优化只能应用于以下函数:

(define (fac n)
  (if (= n 0)
      1
      (* n (fac (- n 1)))))
(define (factorial n)
    (let fact ([i n] [acc 1])
      (if (zero? i)
          acc
          (fact (- i 1) (* acc i)))))

否,无法优化第一个
fac

调用函数时,您需要知道调用函数的位置,以便在调用完成后返回该位置,并在将来的计算中使用调用结果(a
fac
函数)


事实
的实现方式不同。
事实
所做的最后一件事就是调用自身。不需要记住我们呼叫的地点-相反,我们可以执行尾部呼叫消除。在
事实
返回后,不应执行任何其他操作。

思考尾部调用的一个有用方法是询问“递归过程调用的结果必须发生什么?”

第一个函数不能进行尾部优化,因为必须使用对
fac
的内部调用的结果,并乘以
n
,以生成对
fac
的整体调用的结果

然而,在第二种情况下,对
fact
的“外部”调用的结果是。。。对
fact
的内部调用的结果。无需对其执行任何其他操作,后一个值可以直接作为函数的值传回。这意味着不需要保留其他函数上下文,因此可以简单地丢弃它

R5RS标准通过使用a的概念来定义“尾部调用”,这基本上就是我上面描述的