是否可以由编译器/解释器针对以下给出的阶乘函数执行尾部调用优化?
(define factorial
(lambda (x)
(if (= x 0)
1
(* x (factorial (- x 1))))))
我想对此做一个简短的解释。
从下面@rsm的评论中,我了解程序应该写成这样:
(define fact
(lambda (x accumulator)
(if (<= x 1)
accumulator
(fact (- x 1) (* x accumulator)))))
(define factorial
(lambda (x)
(fact x 1)))
或者类似这样的东西:
(define factorial
(lambda (n)
(let fact ([i n] [a 1])
(if (= i 1)
a
(fact (- i 1) (* a i))))))
答案 0 :(得分:1)
首先,一个术语问题:作为程序员,您不能“执行”尾部调用优化。 (这是“尾部调用优化”对该属性使用不好的名称的原因之一。)在这种情况下,“优化”由评估者完成;具体来说,正确的Racket或Scheme评估程序或任何适当的尾调用语言都可以保证:它承诺不要在某些类型的程序上使用无限制的内存。具体来说,仅进行“尾部调用”的程序。
因此,您真正要问的是如何将程序转换为仅进行尾部调用的程序。此处的关键是了解尾调用,并将程序转换为累加器样式。而且,在这一点上,我将参考Alexis King's answer中出现的精彩讨论。
答案 1 :(得分:-1)
您似乎正在尝试计算x!
。
您使用输入x
将阶乘定义为 lambda (此处它是可读的伪代码,而不是Scheme中的前缀语法):
factorial (x) = {
(x=0) -> 1 // end condition
(x<>0) -> x * fact(x-1) // 'fact' should be 'factorial' AFAIK
}
或换句话说:
factorial(x) * factorial(x-1) * factorial((x-1)-1) ...factorial(0) => x!
以下已是尾递归(递归是最后一次调用是递归):
factorial (x , sum(1)) = {
(x=0) -> sum // end condition
(x<>0) -> fact(x-1 , sum(x*sum)) // 'fact' should be 'factorial' AFAIK
}
返回代码,应类似于:
(define factorial
(lambda (x , sum=1)
(if (= x 0)
sum
(fact (- x 1) (* x sum)))))