我正在学习圣诞节考试并做一些示例考试问题,我遇到过这个让我感到有些难过的问题
我可以很好地进行常规递归,但是我无法解决如何使用尾递归来编写相同的东西。
常规版:
(define (factorial X)
(cond
((eqv? X 1) 1)
((number? X)(* X (factorial (- X 1))))))
答案 0 :(得分:23)
对于函数是尾递归的,函数返回后必须无事可做,除了返回它的值。也就是说,递归步骤中发生的最后一件事是调用函数本身。这通常通过使用累加器参数来跟踪答案来实现:
(define (factorial x acc)
(if (zero? x)
acc
(factorial (sub1 x) (* x acc))))
上面的过程最初将使用1
作为累加器进行调用,如下所示:
(factorial 10 1)
=> 3628800
请注意,在达到基本情况时会返回累计值,并且在递归调用中的每个点都会更新acc
参数。我不得不在程序中添加一个额外的参数,但是可以通过定义内部过程或名为let
来避免这种情况,例如:
(define (factorial x)
(let loop ((x x)
(acc 1))
(if (zero? x)
acc
(loop (sub1 x) (* x acc)))))