繁体   English   中英

Scheme中的尾递归幂函数

[英]Tail-Recursive Power Function in Scheme

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

(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))

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

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

(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)))))

即使它具有相同的名称,它也不是相同的参数。 如果你深入研究解释器在做什么,你会看到“a”被定义了两次。 一次用于本地作用域,但它仍然记住外部作用域上的“a”。 当解释器调用函数时,它会尝试将参数的值绑定到形式参数。

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

在纯函数式风格中,值永远不会改变,而是您不断使用新值调用函数。 编译器应该能够在紧密循环中编写代码,更新堆栈上的值(尾调用消除)。 通过这种方式,您可以更担心算法的正确性,而不是充当人类编译器,说实话,这是一种非常低效的机器-任务配对。

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


(display (power 3.5 3))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM