为什么我得到“申请不是程序”?

时间:2014-09-28 00:00:07

标签: recursion functional-programming scheme racket tail-recursion

我正在尝试编写一个通过iteratve进程计算f的过程。函数f由

规则定义

f(n)= n,如果n < 4和

f(n)= f(n - 1)+ 2f(n - 2)+ 3f(n - 3)+ 4f(n - 4),如果n> = 4。

这是我的程序:

(define (f n)
  (define (newF temp n)
    (letrec ((first (- n 1))
             (second (- n 2))
             (third/fourth (- n 3))
             (fifth (- n 4)))
      (define (d)
        ((if (< first 4) (set! temp (+ temp first)) (newF temp first))
         (if (< second 4) (set! temp (+ temp (* second 2))) (newF temp second))
         (if (< third/fourth 4) (set! temp (+ temp (* third/fourth 3) (* third/fourth 4))) (newF temp third/fourth))
         (if (< fifth 4) (set! temp (+ temp (* fifth 4)))(newF temp fifth))))
      (d))
    temp)
  (newF 0 n))

不幸的是,当我跑(f 7)时,我收到了这个错误(引用了if语句体):

application: not a procedure;
 expected a procedure that can be applied to arguments
  given: #<void>
  arguments...:
   #<void>
   #<void>
   #<void>

任何人都知道我为什么以及如何解决它的原因?

2 个答案:

答案 0 :(得分:3)

根据your previous question,你以完全必要的方式处理它(当然不正确,否则你不会问这个问题),这不是Scheme喜欢的方式上班。这是编写函数的函数(但不是迭代)方法:

(define (f n)
  (if (< n 4)
      n
      (+ (f (- n 1)) (* 2 (f (- n 2))) (* 3 (f (- n 3))) (* 4 (f (- n 4))))))

现在,让我们看看如何迭代地写这个。首先,让我们看看如何编写迭代的Fibonacci函数:

(define (fib n)
  (let loop ((i 0) (a 0) (b 1))
    (if (>= i n)
        a
        (loop (+ i 1) b (+ a b)))))

这与以下JavaScript的作用相同:

fib = function (n) {
  return (function loop(i, a, b) {
            return i >= n ? a : loop(i + 1, b, a + b);
          })(0, 0, 1);
};

请注意iab实际上如何更新。我们使用尾递归来更新值,而不是通过重新分配/变异(即,不使用JS中的=或Scheme中的set!)。我最近写了一篇关于why tail-recursion is so important in Scheme的答案。

所以,你会做一些与你的功能类似的东西:

(define (f n)
  (let loop ((i 0) (a 0) (b 1) (c 2) (d 3))
    (if (>= i n)
        a
        (loop (+ i 1) b c d (+ d c c b b b a a a a)))))

答案 1 :(得分:2)

报告错误是因为()帮助程序中的表达式存在一些不必要的d。你不必这样做,程序中的所有表达都隐含在begin内,没有必要使用()表示他们全部代码块的一部分 - 此外,当我们用()包围表达式时,解释器会尝试将表达式应用为一个过程 - 因此application: not a procedure错误。

除此之外,还有一些关于风格的评论。在Scheme中,我们尽量避免使用set!,这不是解决此编程语言中的问题的惯用方法。此外,您还在覆盖Racket中的一些内置程序:firstsecondfifth是已在使用的名称,您不应将它们用于您自己的变量。