我正在尝试实现生成器以在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))
答案 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
那样进行单独的过程以在每个过程之间生成大量集合。自从await
和async
的早期版本是生成器和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 +))