如何用发电机实现斐波那契?

时间:2019-06-07 20:06:15

标签: scheme

我正在尝试实现生成器以在Scheme中列出斐波那契数字,但我做不到。 我有两个函数,第一个是以列表形式返回斐波那契数的函数,第二个是生成器函数。

我要做的是最终将Fibonacci函数从Fibonacci数字列表转换为生成器。

;FIBONACCI NUMBERS
(define (fib n a b i)
 (if
  (= i n)
  (list b)
 (cons b (fib n b (+ a b) (+ i 1)))
 )
)
(define (fibonacci n)
 (cond
 ((= n 1) (list 1))
 (else (fib n 0 1 1))
 )
)

;GENERATOR
(define (generator start stop step)
  (let ((current (- start 1)))
  (lambda ()
  (cond ((>= current stop) #f)
  (else
   (set! current (+ current step))
    current)))))

(define (next generator)
 (generator))

2 个答案:

答案 0 :(得分:2)

当您写generators时,人们会想到implemented in Scheme withcall/cc等其他语言中的generators概念。

(define-coroutine (fib)
  (let loop ((a 0) (b 1))
    (yield a)
    (loop b (+ a b))))

(fib) ; ==> 0
(fib) ; ==> 1
(fib) ; ==> 1
(fib) ; ==> 2
(fib) ; ==> 3

现在,这有点像在迭代中制作步进器。它在那里有溪流和传感器。您可以使映射函数按顺序组合操作,从而按项进行计算,而不是像链map那样进行单独的过程以在每个过程之间生成大量集合。自从awaitasync的早期版本是生成器和Promise的组合以来,过去几年中JavaScript的一件大事已与生成器联系起来。

现在,如果您从更一般的意义上进行更多思考,则是处理下一个值的过程。您也可以这样:

(define fib 
  (let ((a 0) (b 1))
    (lambda ()
      (let ((result a))
        (set! a b)
        (set! b (+ result b))
        result))))

(fib) ; ==> 0
(fib) ; ==> 1
(fib) ; ==> 1
(fib) ; ==> 2
(fib) ; ==> 3

如您所见,这通过更新私有绑定来完成任务。它比花哨的真实生成器还要面向对象。

答案 1 :(得分:1)

由于Sylwester提到了流,因此这里是stream解决方案-

(define fib
  (stream-cons 0
               (stream-cons 1
                            (stream-add fib
                                        (stream-rest fib)))))


(stream->list (stream-take fib 20))
; '(0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181)

stream-add将使用+和流原语将两(2)个流加在一起-

(define (stream-add s1 s2)
  (if (or (stream-empty? s1)
          (stream-empty? s2))
      empty-stream
      (stream-cons (+ (stream-first s1)
                      (stream-first s2))
                   (stream-add (stream-rest s1)
                               (stream-rest s2)))))

或者您可以采用更通用的方法,该方法允许使用任何过程和任意数量的流-

(define ((stream-lift f) . s)
  (if (ormap stream-empty? s)
      empty-stream
      (stream-cons (apply f (map stream-first s))
                   (apply (stream-lift f) (map stream-rest s)))))

(define stream-add (stream-lift +))