Scheme 格式中的迭代树计算

Scheme 格式中的迭代树计算,scheme,iteration,racket,Scheme,Iteration,Racket,我正在尝试实现一个定义如下的函数: f(n) = n if n < 4 f(n) = f(n - 1) + 2f(n - 2) + 3f(n - 3) + 4f(n - 4) if n >= 4 实施尝试: ; m1...m4 | The results of the previous calculations (eg. f(n-1), f(n-2), etc.) ; result | The result thus far ; counter | The current ite

我正在尝试实现一个定义如下的函数:

f(n) = n if n < 4
f(n) = f(n - 1) + 2f(n - 2) + 3f(n - 3) + 4f(n - 4) if n >= 4
实施尝试:

; m1...m4 | The results of the previous calculations (eg. f(n-1), f(n-2), etc.)
; result  | The result thus far
; counter | The current iteration of the loop--starts at 4 and ends at n
(define (fourf-iter n)
  (cond [(< n 4) n]
        [else
         (define (helper m1 m2 m3 m4 result counter)
           (cond [(= counter n) result]
                 [(helper result m1 m2 m3 (+ result m1 (* 2 m2) (* 3 m3) (* 4 m4)) (+ counter 1))]))
         (helper 3 2 1 0 10 4)]))
;m1…m4 |先前计算的结果(如f(n-1)、f(n-2)等)
; 结果|到目前为止的结果
; 计数器|循环的当前迭代——从4开始,到n结束
(定义(fourf iter n)
(cond[(
几个问题:

  • 返回的结果比预期的结果少了一次迭代,因为实际的计算直到递归调用才发生
  • 我没有使用定义的算法来计算f(4),而是把它放在那里,
    f(4)=10
  • 理想情况下,我希望从0开始计算
    result
    ,从3开始计算
    counter
    ,以便将计算应用到
    m1
    m4
    (并且
    f(4)
    将实际计算出来,而不是预设),但是在下一次迭代中,
    0
    用于m1,此时它应该是
    f(4)
    的结果(
    10
tl;dr结果计算延迟或结果本身延迟。如何正确地编写这个函数?

我认为编写递归定义的函数的合适的“Scheme-ish”方法是使用memonization。如果函数
f
被记忆,那么当您调用
f(4)
时,它首先在键值表中查找
4
,如果找到它,则返回存储的值。否则,它只需正常计算,然后将计算出的内容存储在表中。因此,
f
永远不会对同一计算进行两次计算。这类似于创建一个大小为
n
的数组并填充从0开始的值,为
n
构建解决方案的模式。这种方法被称为动态规划,而记忆和动态规划是看待同一优化策略的两种不同方式——避免重复计算同一事物。下面是一个简单的Racket函数
memo
,它接受一个函数并返回该函数的一个记忆版本:

(define (memo f)
  (let ([table (make-hash)])
    (lambda args
      (hash-ref! table
                 args
                 (thunk (apply f args))))))
现在,我们可以递归地编写函数
f
,而不必担心两次计算相同结果的性能问题,从而从指数时间算法变为线性算法,同时保持实现简单:

(define f
  (memo
    (lambda (n)
      (if (< n 4)
          n
          (+ (f (- n 1))
             (* 2 (f (- n 2)))
             (* 3 (f (- n 3)))
             (* 4 (f (- n 4))))))))
使用此选项可以使问题的尾部递归解决方案比定义帮助函数并调用它要简单得多:

(define (f n)
  (if (< n 4)
      n
      (let loop ([a 3] [b 2] [c 1] [d 0] [i 4])
        (if (<= i n)
            (loop (fn+1 a b c d) a b c (add1 i))
            a))))

(define (fn+1 a b c d)
  (+ a (* 2 b) (* 3 c) (* 4 d)))
(定义(f n)
(如果((如果相关的:那很有趣,我会记住的,谢谢。如果我必须让f tail递归,我会怎么做?
(define (display-n string n)
  (let loop ([i 0])
    (when (< i n)
        (display string)
        (loop (add1 i)))))
(define (f n)
  (if (< n 4)
      n
      (let loop ([a 3] [b 2] [c 1] [d 0] [i 4])
        (if (<= i n)
            (loop (fn+1 a b c d) a b c (add1 i))
            a))))

(define (fn+1 a b c d)
  (+ a (* 2 b) (* 3 c) (* 4 d)))