1

我正在尝试编写一个函数,它使用给定的运算符累积值区间并添加初始值。例子:

(累积间隔 + 0 2 4):2 + 3 + 4 + 0 = 9

(累积间隔 * 1 2 5):2 * 3 * 4 * 5 * 1 = 120

注意:只有 (+) 和 (*) 工作对我来说就足够了。

我的代码是:

(define accumulate-interval
  (lambda (op init lower upper) (if (= upper lower)
   (lambda (x) (op x init))
    (lambda (x)
      (op
      ((accumulate-interval op init lower (- upper 1)) x))))     ))

它返回一个过程而不是一个值。如果您能提供帮助,我将不胜感激。

4

2 回答 2

2

您的代码中有几个概念性问题。我同意@itsbruce,向您指出正确的解决方案比修复问题中发现的每个错误更简单。

首先,请注意该过程可以根据现有的高阶函数来编写:foldr用于累积值和build-list创建值范围:

(define (accumulate-interval op init lower upper)
  (foldr op init
         (build-list (add1 (- upper lower))
                     (lambda (x) (+ lower x)))))

或者,在 Racket 中,您可以使用它for/list来创建值范围:

(define (accumulate-interval op init lower upper)
  (foldr op init
         (for/list ([n (in-range lower (add1 upper))]) n)))

如果需要从头开始编写解决方案(可能就是这种情况),最好将问题分成几部分。首先,生成数字范围:

(define (range lower upper)
  (if (> lower upper)
      '()
      (cons lower
            (range (add1 lower) upper))))

现在,累积值:

(define (accumulate op init lst)
  (if (null? lst)
      init
      (op (car lst)
          (accumulate op init (cdr lst)))))

最后,将前面的两个辅助过程组合成一个问题的解决方案。请注意,在前两个解决方案中,我们做了完全相同的问题分解(第一个:生成范围;第二个:累积;第三个:组合),唯一的区别是这里我们手动编写了帮助程序,而不是使用已经存在的程序:

(define (accumulate-interval op init lower upper)
  (accumulate op init
              (range lower upper)))

当然,您可以像在您的解决方案中一样将所有过程合并为一个 - 它更有效,因为它不会创建中间数字列表:

(define (accumulate-interval op init lower upper)
  (if (> lower upper)
      init
      (op lower
          (accumulate-interval op init (add1 lower) upper))))

...但是这样做只会为一个特定问题提供量身定制的解决方案,而不是一组在其他情况下有用的可组合程序。在函数式编程风格中,最好定义通用的、可重用的函数。

无论如何,这按预期工作:

(accumulate-interval + 0 2 4)
> 9

(accumulate-interval * 1 2 5)
> 120
于 2012-10-16T15:35:34.540 回答
1

它返回一个函数,因为这就是您要返回的。 lambda是一个创建匿名函数并返回对它的引用的函数。当您的代码执行

(define accumulate-interval (lambda (op init lower upper) ......))

它使用lambda创建一个匿名函数,返回对它的引用并将该引用分配为accumulate-interval的值。 因此, accumulate-interval与该函数相关联,并且只要在列表中的函数位置评估累积间隔时,就会运行该函数。

现在,您的累积间隔函数由一个if表达式组成

(if (= upper lower) (lambda (x) ...) (lambda (x) ...))

因此,如果upperlower相等,则返回一个匿名函数的引用,否则返回不同的。这就是你告诉它要做的事情。

我不知道你在这里想要做什么,但我怀疑你只是想执行你错误地包装在一个函数中并返回的代码。所以我认为你的代码看起来更像

(if (= upper lower)
  (op upper init) (op lower (accumulate-interval op init (+ lower 1) upper)))

哪个应该起作用,尽管我认为您需要重新考虑您的论点,因为该递归调用不在尾部位置。

考虑此事,

(if (= upper lower)
   (op upper init)
   (accumulate-interval (op upper init) lower (- upper 1)))

可以工作并且是尾递归的。

注意:我通常不会为人们做功课,但我认为您可能对 Scheme 语法有不止一个误解,显示工作代码比单独和组合探索每个可能的误解更容易。

于 2012-10-16T15:19:53.580 回答