Scheme中的Fibonacci程序(使用define-datatype)

时间:2013-11-25 21:36:13

标签: types scheme fibonacci

我一直在尝试使用 define-datatype 方法在方案中编写Fibonacci程序,但我无法这样做。请告诉我它是如何完成的。

我在下面写了表示独立代码:

(define (top-k k)
   k)

(define (applyk k n)
  (k n))

(define (fibind n k)
  (cond
   [(= n 0) (k 1)]
   [(= n 1) (k 1)]
   [else (fibind (- n 1) (fib1 n k))]))

(define fib1
  (lambda (n k)
    (lambda (v)
      (fibind (- n 2) (lambda (w) (k (+ v w)))))))

编辑:我基本上想要一个找到斐波纳契数字的代码(类似于下面的代码)

;;;;k:: []-> continuation?
(define-datatype k k?
 [topk]
 [fact1-k (n number?) (saved-k k?)])

;;;appylk:: nat? continuation? -> nat?
(define apply-k
  (lambda (v c)
  (cases k c
   [topk () v]
   [fact1-k (n saved-k)
      (apply-k (* n v) saved-k)])))

;;;fact :: nat? continuation? -> nat? 
(define (fact n k)
   (if (< n 2)
      (apply-k n k)
      (fact (- n 1) (fact1-k n k))))

2 个答案:

答案 0 :(得分:4)

您的代码使您看起来像是在尝试以延续传递方式执行此操作。首先,让我们来看看实现n斐波纳契数的天真直接方式:

(define (fib n)
  ;; This is a naïve implementation, and will get 
  ;; *very* slow, *very* quickly.  It's much more 
  ;; common to implement this as an iterative process
  (cond
    ((= n 0) 1)
    ((= n 1) 1)
    (else (+ (fib (- n 1))
             (fib (- n 2))))))

现在,为了将其转化为延续传递风格,我们只是在某些事情发生时分解。对于n01的情况,我们只需使用1调用延续。但是,在递归的情况下,我们需要计算(- n 1)的斐波那契数(称之为f1),并用它来调用一些延续。然而,这种延续不是k,因为仍有工作要做;我们仍然需要(- n 2)的数字!延续使用f1作为参数,并为我们计算(- n 2)的斐波纳契数(称为f2)并且必须使用它来调用某些延续。不过,这种延续也不是k。新的续约可以访问f1f2,并且它们的总和是k所需要的:

(define (fib% n k)
  (cond
    ((= n 0) (k 1))
    ((= n 1) (k 1))
    (else (fib% (- n 1)
                (lambda (f1)
                  (fib% (- n 2)
                        (lambda (f2)
                          (k (+ f1 f2)))))))))
> (fib% 1 display)
1
> (fib% 5 display)
8
> (fib% 8 display)
34

但是,有更多有效的方法来计算Fibonacci序列中的数字。典型的一个以1和1开始,然后计算下一个值(2),将其添加到前一个值(1)得到3,将前一个值(2)加到得到5,将其加到前一个值( 3)得到8,依此类推。看起来像是:

(define (fib-it n)
  ;; This is much more efficient, since it moves
  ;; computes the numbers in the sequence sequentially.
  (let fib ((a 1) (b 1) (n n))
    (if (zero? n)
        a
        (fib b (+ a b) (sub1 n)))))

除了命名的let函数fib返回a而不是用它调用k之外,这几乎已经是连续传递样式了。这可以通过以下方式完成:

(define (fib-it% n k)
  (let fib ((a 1) (b 1) (n n))
    (if (zero? n)
        (k a)
        (fib b (+ a b) (sub1 n)))))

这并不觉得它已经完成了,因为它是一个函数的延续传递样式版本,无论如何都不会进行任何自我递归调用;名为let的迭代处理了这个问题。我们不妨写下以下内容,但这并不是很有趣:

(define (fib-it% n k)
  (k (let fib ((a 1) (b 1) (n n))
       (if (zero? n)
           a
           (fib b (+ a b) (sub1 n))))))

答案 1 :(得分:1)

以下是斐波纳契CPS表示独立的代码,

#lang racket

(define top-k
  (lambda(v)
    v))

(define fib
  (lambda (n)
    (fib/k n top-k)))

(define fib/k
  (lambda (n k)
    (cond 
      [ (= 1 n)
                (apply-k k 0) ]
      [ (= 2 n)
                (apply-k k 1) ]

      (else
           (fib/k (sub1 n) (fib1-k n k) )
      )
    )
  )
)

(define fib1-k
  (lambda (n k)
    (lambda(v)
      (fib/k (- n 2) (fib2-k v k))
      )))


(define fib2-k
  (lambda(v k)
    (lambda (w)
      (apply-k k (+ w v))
    )))



(define apply-k
  (lambda(k v)
    (k v)))

有关详细信息,请参阅本书Essentials of Programming Languages

的第198页

我不知道你在说什么,因为独立的代表是真的如此。