Generator Utilities
(require generator-util) | package: generator-util |
Primitives and utilities for working with generators.
This module provides general-purpose utilities to achieve standard sequence-style transformations with generators without losing the laziness and constant-memory guarantees that generators provide.
These utilities are not suitable for use in all cases. In particular, they are not suitable for use with coroutines – i.e. in cases where there is bidirectional communication with a generator. Some of the utilities below wrap underlying generators with intermediary ones, and values sent to them are not conveyed to the underlying generators.
1 Primitives
procedure
(generator-null [return]) → generator?
return : any/c = (void)
procedure
(generator-cons v g) → generator?
v : any/c g : generator?
procedure
(make-generator v ...) → generator?
v : any/c
> (define g (generator-cons 1 (generator-null))) > (g) 1
> (void? (g)) #t
> (define g (generator-cons 1 (generator-null 23))) > (g) 1
> (g) 23
> (define g (make-generator 1 2 3)) > (g) 1
> (->list g) '(2 3)
procedure
(generator-done? g) → boolean?
g : generator?
procedure
(generator-empty? g) →
boolean? generator? g : generator?
generator-empty? returns both a boolean value indicating whether the generator is empty or not, as well as a fresh generator intended to supplant the original generator in the calling context. This is necessary because checking for emptiness requires invoking the generator to inspect the first element, which mutates the original generator. The returned generator is equivalent to the original generator prior to the mutation, modulo the aforementioned caveat about coroutines.
> (define g (make-generator)) > (generator-done? g) #f
> (define-values (is-empty? g) (generator-empty? g)) > is-empty? #t
> (generator-done? g) #f
> (g) > (generator-done? g) #t
procedure
(generator-peek g) →
any/c generator? g : generator?
> (define g (make-generator 1 2 3)) > (define-values (v g) (generator-peek g)) > v 1
> (g) 1
> (g) 2
> (g) 3
2 Utilities
procedure
(generator-map f g) → generator?
f : (-> any/c any/c) g : generator?
> (define g (make-generator 1 2 3)) > (define g (generator-map add1 g)) > (g) 2
> (g) 3
> (g) 4
procedure
(generator-filter f g) → generator?
f : (-> any/c boolean?) g : generator?
> (define g (make-generator 1 2 3 4 5)) > (define g (generator-filter odd? g)) > (g) 1
> (g) 3
> (g) 5
procedure
(generator-fold f g [base #:order order]) → generator?
f : procedure? g : generator? base : any/c = undefined order : (one-of/c 'abb 'bab) = 'abb
> (define g (make-generator 1 2 3 4)) > (define g (generator-fold + g)) > (g) 1
> (g) 3
> (g) 6
> (g) 10
procedure
(generator-append a b) → generator?
a : generator? b : generator?
> (define a (make-generator 1 2)) > (define b (make-generator 3 4)) > (define g (generator-append a b)) > (g) 1
> (g) 2
> (g) 3
> (g) 4
procedure
(generator-zip g ...) → generator?
g : generator?
procedure
(generator-zip-with f g ...) → generator?
f : procedure? g : generator?
> (define a (make-generator 1 2)) > (define b (make-generator 'a 'b)) > (define c (make-generator 'A 'B)) > (define g (generator-zip a b c)) > (g) '(1 a A)
> (g) '(2 b B)
> (define a (make-generator 1 2)) > (define b (make-generator 1 2)) > (define c (make-generator 1 2)) > (define g (generator-zip-with + a b c)) > (g) 3
> (g) 6
procedure
(generator-join g) → generator?
g : generator?
> (define g (make-generator (list 1) (list 2) (list 3))) > (define g (generator-join g)) > (g) 1
> (g) 2
> (g) 3
procedure
(generator-flatten g) → generator?
g : generator?
> (define g (make-generator (list (list (list 1))) (list (list (list 2))) (list (list (list 3))))) > (define g (generator-flatten g)) > (g) 1
> (g) 2
> (g) 3
procedure
(yield-from g) → any
g : generator?
> (define g (generator () (yield-from (make-generator 1 2 3)))) > (g) 1
> (g) 2
> (g) 3
3 Interface
value
> (struct api-reader (source) #:transparent #:property prop:procedure (λ (self) ((api-reader-source self))) #:methods gen:generator [(define/generic -generator-state generator-state) (define (generator-state st) (-generator-state (api-reader-source source)))]) > (define g (api-reader (make-generator 1 2 3))) > (g) 1
> (->list g) (list (generator #<procedure:generator>))
To implement this interface for custom types, the following method needs to be implemented:
procedure
(generator-state v)
→ [symbol? (one-of/c 'fresh 'suspended 'running 'done)] v : generator?
procedure
(generator? v) → boolean?
v : any/c
> (generator? 3) #f
> (generator? (generator () (void))) #t
> (generator? (generator-cons 1 (generator-null))) #t
procedure
(in-producer g [stop] v ...) → sequence?
g : generator? stop : any/c = undefined v : any/c
> (define g (make-generator 1 2 3)) > (->list (in-producer g (void))) '(1 2 3)