例如,
(require racket/generator)
(define f add1)
(define init 0)
(in-producer (generator () (let loop ([x init]) (yield x) (loop (f x)))))
还有更好的方法吗?我不太喜欢生成器,因为它们具有隐藏状态。
答案 0 :(得分:2)
使用streams可能是最简单的:
(require racket/stream)
;; X [X -> X] -> [Streamof X]
(define (repeated-fn-stream init f)
(stream-cons init (repeated-fn-stream (f init) f)))
(repeated-fn-stream 0 add1)
或者,使用序列和make-do-sequence
:
(require racket/sequence)
;; X [X -> X] -> [Sequenceof X]
(define (repeated-fn-sequence init f)
;; A "Pos" is an X that's the result of applying f repeatedly to init
(define (pos->element pos) pos)
(define (next-pos pos) (f pos))
(define init-pos init)
(make-do-sequence
(λ ()
(values pos->element
next-pos
init-pos
#false
#false
#false))))
(repeated-fn-sequence 0 add1)
如果要使用序列,请使用define-sequence-syntax
来使for
循环专门化:
(“纯”功能完全不需要,但是可能具有不同的性能特征)
(require (for-syntax syntax/parse))
(define-sequence-syntax in-repeated-fn-sequence
(λ () #'repeated-fn-sequence) ; when used as a normal expression
(syntax-parser ; when used *directly* as a for-loop clause
[[(x) (_ init-expr f-expr)]
#'[(x) (:do-in
([(init) init-expr] [(f) f-expr])
#true
([x init])
#true
()
#true
#true
[(f x)])]]))
(for/list ([x (in-repeated-fn-sequence 0 add1)]
[i (in-range 10)])
x)
使用define-sequence-syntax
时,应确保所有内容都存在“单一事实点” 。因此,您经常会看到这种模式:
(define-sequence-syntax in-___
(λ () #'in-___/proc) ; when used as a normal expression
(syntax-parser
....everything that defines the actual functionality....))
;; This is completely determined by the sequence-syntax above,
;; that way there is NO duplicated functionality and NO chance for
;; it to get "out of sync".
(define (in-___/proc parameter ...)
(for/stream ([elem (in-___ parameter ...)])
elem))
这意味着什么,一旦您决定要使用define-sequence-syntax
,就应根据其定义repeated-fn-sequence
函数:
(define (repeated-fn-sequence init f)
(for/stream ([elem (in-repeated-fn-sequence init f)])
elem))
这样,如果需要更改in-repeated-fn-sequence
来修复错误或切换表示形式,则功能版本会随之自动更改。
答案 1 :(得分:2)
这项工作的最佳功能是展开…,但是很遗憾,Racket没有提供内置的sequence-unfold
或stream-unfold
操作。但是,stream-unfold
库中有一个srfi/41
操作,可以满足您的需求。您可以在以下程序中看到这一点:
#lang racket
(require (only-in srfi/41 stream-unfold))
(define nats (stream-unfold identity (const #t) add1 0))
(for/list ([i (in-range 20)] [n nats]) n)
这将产生以下输出:
'(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)
如果您不想使用srfi/41
,则可以使用stream-unfold
API自己编写racket/stream
,而不会太困难,也没有任何有状态性:
(define (stream-unfold mapper pred? gen base)
(let loop ([base base])
(if (pred? base)
(stream-cons (mapper base) (loop (gen base)))
empty-stream)))