如何反复应用函数以获得无限序列?

时间:2018-08-27 05:54:02

标签: racket

例如,

(require racket/generator)
(define f add1)
(define init 0)
(in-producer (generator () (let loop ([x init]) (yield x) (loop (f x)))))

还有更好的方法吗?我不太喜欢生成器,因为它们具有隐藏状态。

2 个答案:

答案 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-unfoldstream-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)))