Recursion 在scheme中创建尾部递归幂函数

Recursion 在scheme中创建尾部递归幂函数,recursion,scheme,tail-recursion,Recursion,Scheme,Tail Recursion,我想知道如何在scheme中实现尾部复活功率函数 我已经为scheme定义了递归: (define power-is-fun (lambda (x y) (cond [(= y 0) 1] [(> y 0) (* (power-is-fun x (- y 1)) x)]))) 但是我不能很好地理解另一个应该是什么。答案是类似的,您只需将累积结果作为参数传递: (define power-is-fun (lam

我想知道如何在scheme中实现尾部复活功率函数

我已经为scheme定义了递归:

(define power-is-fun
  (lambda (x y)
    (cond [(= y 0)
           1]
          [(> y 0)
           (* (power-is-fun x (- y 1)) x)])))

但是我不能很好地理解另一个应该是什么。

答案是类似的,您只需将累积结果作为参数传递:

(define power-is-fun
  (lambda (x y acc)
    (cond [(= y 0)
           acc]
          [(> y 0)
           (power-is-fun x (- y 1) (* x acc))])))
这样调用它,注意
acc
的初始值是
1
(您可以为此构建一个帮助函数,因此您不必每次都记住传递
1
):

将递归过程转换为尾部递归的一些常规指针:

  • 向函数中添加一个额外参数,以保存迄今为止累积的结果
  • 在第一次调用过程时传递累加器的初始值,通常这与在“正常”(非尾部递归)递归的基本情况下返回的值相同
  • 在递归的基本情况下返回累加器
  • 在递归步骤中,使用新值更新累积结果,并将其传递给递归调用
  • 最重要的是:当需要调用递归时,确保将其作为最后一个表达式调用,而不需要执行“额外的工作”。例如,在原始代码中,您在调用
    power is fun
    后执行了乘法,而在尾部递归版本中,对
    power is fun
    的调用是退出过程之前发生的最后一件事

斯卡尔的建议清单非常棒

如果您喜欢更深入地处理迭代(也称为线性递归)和树递归过程,那么不要错过SICP中的伟大处理:


顺便说一句,有一种更快的方法可以实现整数幂运算。与其将
x
一次又一次地乘以
y
次(这使其成为O(y)),还有一种时间复杂度为O(logy)的方法:

(define (integer-expt x y)
  (do ((x x (* x x))
       (y y (quotient y 2))
       (r 1 (if (odd? y) (* r x) r)))
      ((zero? y) r)))
如果您不喜欢
do
(正如我认识的许多Schemer所做的那样),这里有一个tail显式递归的版本(当然,您也可以使用命名的
let
来编写它):


(顺便说一句,任何合适的方案实现都应该将两个版本宏扩展为完全相同的代码。此外,就像奥斯卡的解决方案一样,我使用累加器,只是在这里我称之为
r
(用于“结果”)。

非常感谢。。。其他地方难以获得的信息:)
(define (integer-expt x y)
  (do ((x x (* x x))
       (y y (quotient y 2))
       (r 1 (if (odd? y) (* r x) r)))
      ((zero? y) r)))
(define (integer-expt x y)
  (define (inner x y r)
    (if (zero? y) r
        (inner (* x x)
               (quotient y 2)
               (if (odd? y) (* r x) r))))
  (inner x y 1))