方案中的尾递归幂函数

时间:2013-09-29 20:07:09

标签: function recursion scheme tail-recursion tail

我在编写一个尾递归幂函数时遇到问题。我想使用辅助函数编写函数。我知道我需要一个参数来保持累积值,但是之后我被困住了。我的代码如下。

(define (pow-tr a b)
(define (pow-tr-h result)
  (if (= b 0)
     result
     pow-tr a (- b 1))(* result a)) pow-tr-h 1)

我编辑了我的代码,现在它可以工作了。它如下:

(define (pow-tr2 a b)
 (define (pow-tr2-h a b result)
  (if (= 0 b)
    result
    (pow-tr2-h a (- b 1) (* result a))))
 (pow-tr2-h a b 1))

有人可以向我解释为什么辅助函数应该与main函数具有相同的参数。我很难想到为什么这是必要的。

3 个答案:

答案 0 :(得分:4)

声明“辅助函数应该与主函数具有相同的参数”是不正确的。您只需要在每次迭代中传递将要进行更改的参数 - 在示例中,指数和累积结果。例如,如果不将base作为参数传递,这将正常工作:

(define (pow-tr2 a b)
  (define (pow-tr2-h b result)
    (if (= b 0)
        result
        (pow-tr2-h (- b 1) (* result a))))
  (pow-tr2-h b 1))

它的工作原理是因为内部辅助程序可以“看到”外部主程序中定义的a参数。而且因为基地永远不会改变,我们不必传递它。要了解更多相关信息,请参阅精彩的SICP一书中标题为“内部定义和块结构”的部分。

现在您正在使用帮助程序,最好开始使用named let,这是一种非常方便的语法,用于编写帮助程序而无需显式编写内部过程。上面的代码相当于:

(define (pow-tr2 a b)
  (let pow-tr2-h [(b b) (result 1)]
    (if (= b 0)
        result
        (pow-tr2-h (- b 1) (* result a)))))

答案 1 :(得分:0)

即使它具有相同的名称,它也不是相同的参数。如果你挖掘解释器所做的事情,你会看到两次定义的“a”。一旦为本地范围,但它仍然记得外部范围的“a”。当解释器调用一个函数时,它会尝试将参数的值绑定到形式参数。

你通过相当变异的状态传递值的原因就像你在algol家族语言中所做的那样,通过不改变状态,你可以使用替换模型来推理过程的行为。在任何时候使用参数调用的相同过程将产生与从具有相同参数的任何其他地方调用相同的结果。

在纯粹的功能样式中,值永远不会改变,而是继续使用新值调用函数。编译器应该能够在紧密循环中编写代码,以更新堆栈上的值(尾调用消除)。这样你就可以更多地担心算法的正确性,而不是充当人类编译器,事实上,这是一个非常低效的机器 - 任务配对。

答案 2 :(得分:0)

(define (power a b)
  (if (zero? b)
   1
  (* a (power a (- b 1)))))


(display (power 3.5 3))