diff --git a/collects/scribblings/reference/sequences.scrbl b/collects/scribblings/reference/sequences.scrbl index 692b9ea2a0..f4daf53a8d 100644 --- a/collects/scribblings/reference/sequences.scrbl +++ b/collects/scribblings/reference/sequences.scrbl @@ -1,7 +1,8 @@ #lang scribble/doc @(require "mz.ss" (for-syntax scheme/base) - scribble/scheme) + scribble/scheme + (for-label scheme/generator)) @(define-syntax speed (syntax-rules () @@ -10,6 +11,12 @@ @elem[what] iteration when it appears directly in a @scheme[for] clause.}])) +@(define generator-eval + (lambda () + (let ([the-eval (make-base-eval)]) + (the-eval '(require scheme/generator)) + the-eval))) + @title[#:tag "sequences"]{Sequences} @guideintro["sequences"]{sequences} @@ -296,3 +303,60 @@ second returns the next element (which may be multiple values) from the sequence; if no more elements are available, the @exnraise[exn:fail:contract].} +@section{Iterator Generators} +@defmodule[scheme/generator] +@defform[(generator body ...)]{ Create a function that returns a +value, usually through @scheme[yield], each time it is invoked. When +the generator runs out of values to yield the last value it computed +will be returned for future invocations of the generator. Generators +can be safely nested. + +@examples[#:eval (generator-eval) +(define g (generator + (let loop ([x '(a b c)]) + (if (null? x) + 0 + (begin + (yield (car x)) + (loop (cdr x))))))) +(g) +(g) +(g) +(g) +(g) +] + +To use an existing generator as a sequence you should use @scheme[in-producer] +with a stop-value known to the generator. + +@examples[#:eval (generator-eval) +(define my-stop-value (gensym)) +(define my-generator (generator + (let loop ([x '(a b 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) +]} + +@defproc[(in-generator [expr any?] ...) sequence?]{ Return a generator +that can be used as a sequence. @scheme[in-generator] takes care of the +case when @scheme[expr] stops producing values so when the @scheme[expr] +completes the generator will end. + +@examples[#:eval (generator-eval) +(for/list ([i (in-generator + (let loop ([x '(a b c)]) + (when (not (null? x)) + (yield (car x)) + (loop (cdr x)))))]) + i) +]} + +@defform[(yield expr)]{ Save the point of execution inside a generator +and return a value.} +