【问题标题】:Scheme tail-recursion/iteration方案尾递归/迭代
【发布时间】:2016-05-09 13:00:33
【问题描述】:

我在 scheme 中构建了一个递归函数,它将在某个输入上重复给定函数 f,n 次。

(define (recursive-repeated f n)
  (cond ((zero? n) identity)
        ((= n 1) f)
        (else (compose f (recursive-repeated f (- n 1))))))

我需要用尾递归构建这个函数的迭代版本,如果我正确理解尾递归,我认为我做得对。

(define (iter-repeated f n)
  (define (iter count total)
    (if (= count 0)
        total
        (iter (- count 1) (compose f total))))
  (iter n identity))

我的问题是,这实际上是迭代的吗?我相信我已经使用尾递归正确构建了它,但它仍然在技术上将一堆操作推迟到 count = 0,无论它堆叠多少组合,它都会执行。

【问题讨论】:

  • 为什么会“推迟一堆操作直到 n = 0”?在count = 0,您只返回total,这可能是最简单的工作,几乎没有任何成本。
  • 对,但我想我的意思是,当您返回总计时,它会返回像(compose square (compose square (compose square (identity x)))) 这样的操作堆栈,它会在返回总计时进行评估,而不是在尾调用发生时.还是我这样想太多了?
  • @EddieV 函数的所有参数都在调用函数之前进行评估。
  • 我明白了。好吧,我想那是有道理的,谢谢!
  • 虽然它是迭代的,但你最终返回的是一个大而粗糙的 la​​mbdas 巢。下面 Noamik 的回答为您提供了一种不搞乱的方法。

标签: recursion scheme iteration racket tail-recursion


【解决方案1】:

你提出了一个很好的问题。您从构建递归过程 ((f (f (f ...)))) 的递归过程 (recursive-repeated) 转到构建相同递归过程的迭代过程 (iter-repeated)。

你认为你基本上做了同样的事情是对的,因为最终结果是一样的。您刚刚以两种不同的方式构建了相同的链。这是在您的实现中使用compose 的“后果”。

考虑这种方法

(define (repeat n f)
  (λ (x)
    (define (iter n x)
      (if (zero? n)
          x
          (iter (- n 1) (f x))))
    (iter n x)))

在这里,我们不会提前构建完整的函数调用链,而是返回一个等待输入参数的 lambda。指定输入参数后,我们将以迭代方式在 lambda 内部循环 n 次。

让我们看看它的工作原理

(define (add1 x) (+ x 1))

;; apply add1 5 times to 3
(print ((repeat 5 add1) 3)) ;; → 8

【讨论】:

    猜你喜欢
    • 2015-03-16
    • 2011-11-14
    • 2017-03-08
    • 1970-01-01
    • 1970-01-01
    • 2016-04-07
    • 2012-02-20
    • 2015-03-24
    • 2016-06-14
    相关资源
    最近更新 更多