【问题标题】:SICP recursive process vs iterative process: using a recursive procedure to generate an iterative processSICP递归过程与迭代过程:使用递归过程生成迭代过程
【发布时间】:2013-06-19 16:57:12
【问题描述】:

在SICPSection 1.2.1 作者下面给出这样一个代码示例来展示如何使用迭代过程来解决阶乘问题:

(define (factorial n)
  (fact-iter 1 1 n))
(define (fact-iter product counter max-count)
  (if (> counter max-count)
      product
      (fact-iter (* counter product)
                 (+ counter 1)
                 max-count)))

并说 “我们将诸如 fact-iter 之类的递归过程称为生成迭代过程似乎令人不安。但是,该过程实际上是迭代的:它的状态完全由它的三个状态变量和一个解释器捕获只需跟踪三个变量即可执行流程。”

我不明白作者的意思。递归过程和递归过程有什么区别?为什么他说下面的递归过程生成了一个迭代过程?

【问题讨论】:

    标签: recursion sicp iteration


    【解决方案1】:

    递归过程需要在递归调用进行时维护调用者的状态。例如,如果你写:

    (define (fact-recurse n)
      (if (< n 2)
          1
          (* n (fact-recurse (- n 1)))))
    

    外部调用必须记住n 并等待内部调用返回,然后才能执行乘法运算。如果您调用(fact-recurse 10),当函数到达其递归结束时,将有 9 次堆叠乘法待处理。

    但在迭代过程中,可以丢弃较早的状态。这在示例代码中是可能的,因为所需的所有信息都作为递归调用中的参数传递。不再需要外部调用中的变量,因此不需要将任何内容保存在堆栈中。

    由于不再需要外部调用的参数,递归调用可以翻译成赋值:

    (set! product (* counter product))
    (set! counter (+ counter 1)
    (set! max-count max-count)
    

    然后它只是跳转到程序的开头。

    【讨论】:

    • 这是所有调用优化可能发生的地方,堆栈不再需要并且可以被丢弃,对吗?
    • @JonSurrell 没错。引用的材料解释了尾调用优化是如何发生的。
    猜你喜欢
    • 2017-01-19
    • 2019-02-10
    • 2016-02-24
    • 1970-01-01
    • 2018-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-21
    相关资源
    最近更新 更多