On this page:
generator?
generator
yield
infinite-generator
in-generator
generator-state
sequence->generator
sequence->repeated-generator
4.14.3 Generators

A generator is a procedure that returns a sequence of values, incrementing the sequence each time that the generator is called. In particular, the generator form implements a generator by evaluating a body that calls yield to return values from the generator.

 (require racket/generator) package: base

procedure

(generator? v)  boolean?

  v : any/c
Return #t if v is a generator, #f otherwise.

syntax

(generator formals body ...+)

Creates a generator, where formals is like the formals of case-lambda (i.e., the kw-formals of lambda restricted to non-optional and non-keyword arguments).

For the first call to a generator, the arguments are bound to the formals and evaluation of body starts. During the dynamic extent of body, the generator can return immediately using the yield function. A second call to the generator resumes at the yield call, producing the arguments of the second call as the results of the yield, and so on. The eventual results of body are supplied to an implicit final yield; after that final yield, calling the generator again returns the same values, but all such calls must provide 0 arguments to the generator.

Examples:

> (define g (generator ()
              (let loop ([x '(a b c)])
                (if (null? x)
                    0
                    (begin
                      (yield (car x))
                      (loop (cdr x)))))))
> (g)

'a

> (g)

'b

> (g)

'c

> (g)

0

> (g)

0

procedure

(yield v ...)  any

  v : any/c
Returns vs from a generator, saving the point of execution inside a generator (i.e., within the dynamic extent of a generator body) to be resumed by the next call to the generator. The results of yield are the arguments that are provided to the next call of the generator.

When not in the dynamic extent of a generator, infinite-generator, or in-generator body, yield raises exn:fail after evaluating its exprs.

Examples:

> (define my-generator (generator () (yield 1) (yield 2 3 4)))
> (my-generator)

1

> (my-generator)

2

3

4

Examples:

> (define pass-values-generator
    (generator ()
      (let* ([from-user (yield 2)]
             [from-user-again (yield (add1 from-user))])
        (yield from-user-again))))
> (pass-values-generator)

2

> (pass-values-generator 5)

6

> (pass-values-generator 12)

12

syntax

(infinite-generator body ...+)

Like generator, but repeats evaluation of the bodys when the last body completes without implicitly yielding.

Examples:

> (define welcome
    (infinite-generator
      (yield 'hello)
      (yield 'goodbye)))
> (welcome)

'hello

> (welcome)

'goodbye

> (welcome)

'hello

> (welcome)

'goodbye

syntax

(in-generator maybe-arity body ...+)

 
maybe-arity = 
  | #:arity arity-k
Produces a sequence that encapsulates the generator formed by (generator () body ...+). The values produced by the generator form the elements of the sequence, except for the last value produced by the generator (i.e., the values produced by returning).

Example:

> (for/list ([i (in-generator
                  (let loop ([x '(a b c)])
                    (when (not (null? x))
                      (yield (car x))
                      (loop (cdr x)))))])
    i)

'(a b c)

If in-generator is used immediately with a for (or for/list, etc.) binding’s right-hand side, then its result arity (i.e., the number of values in each element of the sequence) can be inferred. Otherwise, if the generator produces multiple values for each element, its arity should be declared with an #:arity arity-k clause; the arity-k must be a literal, exact, non-negative integer.

Examples:

> (let ([g (in-generator
            (let loop ([n 3])
              (unless (zero? n) (yield n (add1 n)) (loop (sub1 n)))))])
    (let-values ([(not-empty? next) (sequence-generate g)])
      (let loop () (when (not-empty?) (next) (loop))) 'done))

stop?: arity mismatch;

 the expected number of arguments does not match the given

number

  expected: 1

  given: 2

  arguments...:

   3

   4

> (let ([g (in-generator #:arity 2
            (let loop ([n 3])
              (unless (zero? n) (yield n (add1 n)) (loop (sub1 n)))))])
    (let-values ([(not-empty? next) (sequence-generate g)])
      (let loop () (when (not-empty?) (next) (loop))) 'done))

'done

To use an existing generator as a sequence, use in-producer with a stop-value known for the generator:

> (define abc-generator (generator ()
                         (for ([x '(a b c)])
                            (yield x))))
> (for/list ([i (in-producer abc-generator (void))])
    i)

'(a b c)

> (define my-stop-value (gensym))
> (define my-generator (generator ()
                         (let loop ([x (list 'a (void) 'c)])
                           (if (null? x)
                               my-stop-value
                               (begin
                                 (yield (car x))
                                 (loop (cdr x)))))))
> (for/list ([i (in-producer my-generator my-stop-value)])
    i)

'(a #<void> c)

procedure

(generator-state g)  symbol?

  g : generator?
Returns a symbol that describes the state of the generator.

Examples:

> (define my-generator (generator () (yield 1) (yield 2)))
> (generator-state my-generator)

'fresh

> (my-generator)

1

> (generator-state my-generator)

'suspended

> (my-generator)

2

> (generator-state my-generator)

'suspended

> (my-generator)
> (generator-state my-generator)

'done

> (define introspective-generator (generator () ((yield 1))))
> (introspective-generator)

1

> (introspective-generator
   (lambda () (generator-state introspective-generator)))

'running

> (generator-state introspective-generator)

'done

> (introspective-generator)

'running

procedure

(sequence->generator s)  (-> any)

  s : sequence?
Converts a sequence to a generator. The generator returns the next element of the sequence each time the generator is invoked, where each element of the sequence must be a single value. When the sequence ends, the generator returns #<void> as its final result.

procedure

(sequence->repeated-generator s)  (-> any)

  s : sequence?
Like sequence->generator, but when s has no further values, the generator starts the sequence again (so that the generator never stops producing values).