This site is a static rendering of the Trac instance that was used by R7RS-WG1 for its work on R7RS-small (PDF), which was ratified in 2013. For more information, see Home.

Source for wiki GeneratorsGauche version 13

author

cowan

comment


    

ipnr

127.11.51.1

name

GeneratorsGauche

readonly

0

text

{{{
#!html
<h2 class="section">Generators</h2>

<p>A generator is simply a procedure with no arguments that works
as a source of a series of values.  Every time it is called,
it yields a value.  Returning an end-of-file object indicates the generator is exhausted.
For example, <code>read-char</code> can be seen as a generator that
generates characters from the current input port.
</p>
<p>It is common practice to abstract the sources of values in such a way,
so it is useful to define utility procedures that work on 
generators.  This proposal provides them.
</p>
<p>A generator is very lightweight, and useful for implementing simple
on-demand calculations.  However, it's important to keep in mind that it is
side-effecting construct; you can't safely backtrack, for example.
</p>

<p>These procedures are mostly from the Gauche core and the Gauche modules
<code>gauche.generator</code> and <code>data.random</code>, with
some renaming to make them more systematic.</p>

<h3 class="subsection">Generator constructors</h3>

<p>A generator isn't a special datatype but just an ordinary procedure,
so you can construct a generator with <code>lambda</code>.  This module provides
some common generator constructors for convenience.
</p>
<p>If you want to use your procedure as a generator, note that a
generator can be invoked many times even after it returns an end-of-file object once
Once it returns an end-of-file object, it keeps returning
an end-of-file object for all subsequent calls.
</p>
<p>The result of generator constructors is just a procedure,
and printing it doesn't show much.  In the examples in this section
we use <code>generator-&gt;list</code> to convert the generator to the list.
</p>
<p>These procedures have names prefixed with <code>make-</code>
and suffixed with <code>-generator</code>.
<dl>
<dt><code>make-generator</code><i> arg &hellip;</i></dt>
<dd><p>The simplest generator.  Returns the given arguments followed by an end-of-file object when called.
When no arguments are provided, it returns a null generator that generates no values.
</p></dd></dl>

<dl>
<dt><code>make-circular-generator</code><i> arg &hellip;</i></dt>
<dd><p>Returns an infinite generator that repeats the given arguments forever.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(generator-&gt;list (circular-generator 1 2 3) 10)
  &rArr; (1 2 3 1 2 3 1 2 3 1)
</pre></td></tr></table>

<p>Note that the above example limits the length of
the converted list to 10; otherwise
<code>generator-&gt;list</code> won't return.
</p></dd></dl>

<dl>
<dt><code>make-iota-generator</code><i> [ count [ start [ step ] ] ]</i></dt>
<dd><p>Creates a generator
of a series of <var>count</var> numbers (by default, an infinite number),
starting from <var>start</var> (0 by default)
and increased by <var>step</var> (1 by default).
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(generator-&gt;list (make-iota-generator 10 3 2))
  &rArr; (3 5 7 9 11 13 15 17 19 21)
</pre></td></tr></table>

<p>If both <var>start</var> and <var>step</var> are exact, the generator
yields exact numbers; otherwise it yields inexact numbers.  The exactness
of <var>count</var> does not affect the exactness of the results.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(generator-&gt;list (giota +inf.0 1/2 1/3) 6)
  &rArr; (1/2 5/6 7/6 3/2 11/6 13/6)
(generator-&gt;list (giota +inf.0 1.0 2.0) 5)
  &rArr; (1.0 3.0 5.0 7.0 9.0)
</pre></td></tr></table>

</dd></dl>

<dl>
<dt><code>make-range-generator</code><i> start end  [ step ]</i></dt>
<dd><p>Creates a generator of a series of
numbers.  The series begins with <var>start</var>, increases by <var>step</var> (default 1),
and continues while the number is less than <var>end</var>.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(generator-&gt;list (make-range-generator 3 8))
  &rArr; (3 4 5 6 7)
</pre></td></tr></table>
</dd></dl>

<dl>
<dt><code>make-tabulation-generator</code><i> [ k ] proc </i></dt>
<dd><p>Creates a generator
of a series of <var>k</var> numbers (by default, an infinite number), namely
<code>(proc 0)</code>, <code>(proc 1)</code>, <code>(proc 2)</code>, ....
</p>
</dd></dl>

<dl>
<dt><code>make-coroutine-generator</code><i> proc</i></dt>
<dd><p>Creates a generator from a coroutine.
</p>
<p>The <var>proc</var> argument is a procedure that takes one argument,
<var>yield</var>.   When called, <code>generate</code> immediately returns
a generator <var>g</var>.  When <var>g</var> is called, <var>proc</var> runs
until it calls <var>yield</var>.  Calling <var>yield</var> causes
the execution of <var>proc</var> to be suspended, and <var>g</var> returns the value passed
to <var>yield</var>.
</p>
<p>Once <var>proc</var> returns, it is the end of the series &mdash; <var>g</var> returns an
end-of-file object from then on.  The return value of <var>proc</var> is ignored.
</p>
<p>The following code creates a generator that produces a series
0, 1, and 2 (effectively the same as <code>(make-iota-generator 3)</code> and binds
it to <code>g</code>.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(define g
  (generate
   (lambda (yield) (let loop ((i 0))
               (when (&lt; i 3) (yield i) (loop (+ i 1)))))))

(generator-&gt;list g) &rArr; (0 1 2)
</pre></td></tr></table>
</dd></dl>

<dl>
<dt><code>make-list-generator</code><i> lis</i></dt>
<dt><code>make-vector-generator</code><i> vec [ start [ end ] ]</i></dt>
<dt><code>make-reverse-vector-generator</code><i> vec [ start [ end ] ]</i></dt>
<dt><code>make-string-generator</code><i> str [ start [ end ] ]</i></dt>
<dd><p>These procedures return generators that yields each item in the given argument.
A generator returned from <code>make-vector-reverse-generator</code> procedures runs in
reverse order.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(generator-&gt;list (make-list-generator '(1 2 3 4 5)))
  &rArr; (1 2 3 4 5)
(generator-&gt;list (make-vector-generator '#(1 2 3 4 5)))
  &rArr; (1 2 3 4 5)
(generator-&gt;list (make-reverse-vector-generator '#(1 2 3 4 5)))
  &rArr; (5 4 3 2 1)
(generator-&gt;list (make-string-generator &quot;abcde&quot;))
  &rArr; (#\a #\b #\c #\d #\e)
</pre></td></tr></table>

<p>By default the generator is exhausted once all items are retrieved;
the optional <var>start</var> and <var>end</var> arguments can limit the range
the generator walks across.
</p>
<p>For <code>make-reverse-vector-generator</code>, the first value is the item right before
to the <var>end</var> element, and the last value is the <var>start</var>
element.
For all the others, the first value the generator yields
is the <var>start</var>-th element, and it ends right before the <var>end</var>-th element.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">
(generator-&gt;list (make-vector-generator '#(a b c d e) 2))
  &rArr; (c d e)
(generator-&gt;list (make-vector-generator '#(a b c d e) 2 4))
  &rArr; (c d)
(generator-&gt;list (make-reverse-vector-generator '#(a b c d e) 2))
  &rArr; (e d c b)
(generator-&gt;list (make-reverse-vector-generator '#(a b c d e) 2 4))
  &rArr; (d c)
(generator-&gt;list (make-reverse-vector-generator '#(a b c d e) #f 2))
  &rArr; (b a)
</pre></td></tr></table>
</dd></dl>

<dl>
<dt><code>make-bits-generator</code><i> n</i></dt>
<dd><p>This procedure takes an exact integer
considered as a twos-complement value and treats it as a sequence of
boolean values (0 for false and 1 for true), returning bits from
the least significant bit first.  Note that the infinite sequence of
high-order 0 or 1 bits are not returned, so this is a finite generator.
In particular, <code>(make-bits-generator 0)</code> and <code>(make-bits-generator -1)</code>
are both null generators.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(generator-&gt;list (bits-&gt;generator #b10110))
 &rArr; (#f #t #t #f #t)
</pre></td></tr></table>

</dd></dl>

<dl>
<dt><code>make-port-sexp-generator</code><i> input-port</i></dt>
<dt><code>make-port-line-generator</code><i> input-port</i></dt>
<dt><code>make-port-char-generator</code><i> input-port</i></dt>
<dt><code>make-port-byte-generator</code><i> input-port</i></dt>
<dd><p>Returns generators that read characters or bytes from the given
port, respectively.
</p></dd></dl>

<dl>
<dt><code>make-for-each-generator</code><i> for-each obj</i></dt>
<dd><p>A generic generators that converts any collection <var>obj</var> to a generator
that walks across the <var>obj</var> using the <var>for-each</var> procedure
appropriate for <var>obj</var>.
</p></dd></dl>

<dt><code>make-unfold-generator</code><i> stop? mapper successor seed</i></dt>
<dd><p>A generator constructor similar to <code>unfold</code>.
</p>
<p>The <var>stop?</var> predicate takes a seed value and determines
whether to stop.  The <var>mapper </var> procedure calculates a value
to be returned by the generator
from a seed value.  The <var>successor </var> procedure calculates the
next seed value from the current seed value.
</p>
<p>For each call of the resulting generator, <var>stop?</var> is called with
the current seed value.  If it returns true, then the generator
returns an end-of-file object.  Otherwise,
it applies <var>mapper</var> to the current seed value to get the value to
return, and uses <var>g</var> to update the seed value.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(generator-&gt;list (make-unfold-generator (lambda s (&gt; s 5)) (lambda s (* s 2)) (lambda s (+ s 1)) 0))
  &rArr; '(0 2 4 6 8 10)
</pre></td></tr></table>
</dd></dl>

<h3 class="subsection">Generator operations</h3>

<p>The following procedures take generators (notated as <var>gen</var> and
<var>gen<sub>2</sub></var>) and return a generator.  For the convenience, they
also accept any collection to <var>gen</var> and <var>gen<sub>2</sub></var> parameters;
if a collection is passed where a generator is expected,
it is implicitly coerced into a generator.
</p>
<p>The names of these procedures are prefixed with <code>g</code>.
</p>

<dl>
<dt><code>gcons*</code><i> item &hellip; gen</i></dt>
<dd><p>Returns a generator that adds <var>item</var>s in front of <var>gen</var>.
Once the <var>items</var> have been consumed, the generator is guaranteed to
tail-call <var>gen</var>.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(generator-&gt;list (gcons* 'a 'b (giota 2)))
 &rArr; (a b 0 1)
</pre></td></tr></table>
</dd></dl>

<dl>
<dt><code>gappend</code><i> gen &hellip;</i></dt>
<dd><p>Returns a generator that yields the items from the first given
generator, and once it is exhausted, use the second generator, and so on.
Calls to the returned generator are guaranteed to tail-call
one of the generator arguments until they are exhausted.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(generator-&gt;list (gappend (giota 3) (giota 2)))
 &rArr; (0 1 2 0 1)

(generator-&gt;list (gappend))
 &rArr; ()
</pre></td></tr></table>
</dd></dl>

<dl>
<dt><code>gconcatenate</code><i> gen</i></dt>
<dd><p>The <var>gen</var> argument is a generator of generators.
Returns a generator that yields the results from the first generator/sequence,
then the second one, then the third, etc.
</p>
<p>It is similar to <code>(apply gappend (generator-&gt;list gen))</code>, except
that <code>gconcatenate</code> can work even if <var>gen</var> generates an infinite
number of generators.  Calls to the returned generator are guaranteed to tail-call
one of the generators provided by <var>gen</var> until they are exhausted.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">
(generator-&gt;list
  (gconcatenate
    (make-element-generator (giota 3) (giota 2))))
 &rArr; (0 1 2 0 1)
</pre></td></tr></table>
</dd></dl>

<dl>
<dt><code>gmerge</code><i> comparator gen gen<sub>2</sub> &hellip;</i></dt>
<dt><code>gunion</code><i> comparator gen gen<sub>2</sub> &hellip;</i></dt>
<dt><code>gintersection</code><i> comparator gen gen<sub>2</sub> &hellip;</i></dt>
<dd><p>Creates a generator that yields elements out of input generators,
with the order determined by a SRFI 114 comparator.
<code>Gmerge</code> returns all the elements;
<code>gunion</code> returns all the elements that are distinct in the sense of the comparator;
<code>gintersection</code> returns all the elements that appear in all the generators.
</p>
<p>Each input generator must yield appropriately ordered elements by itself;
otherwise the result won't be ordered.
</p>
<p>If only one generator is given, it is just returned.
In that case, <var>comparator</var> is ignored.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(generator-&gt;list (gmerge &lt; '(1 3 8) '(5) '(2 4)))
  &rArr; '(1 2 3 4 5 8)
</pre></td></tr></table>
</dd></dl>

<dl>
<dt><code>gmap</code><i> proc gen gen<sub>2</sub> &hellip;</i></dt>
<dd><p>Returns a generator that yields a value returned by <var>proc</var>
applied on the values from given generators.  The returned generator
terminates when any of the given generator is exhausted.
</p>
<p>Note: This differs from <code>generator-collect</code>,
which consumes all
values at once and returns the results as a list, while <code>gmap</code>
returns a generator immediately without consuming input.
</p></dd></dl>

<dl>
<dt><code>gfold</code><i> proc seed gen gen<sub>2</sub> &hellip;</i></dt>
<dd><p>A generator analogue of <code>fold</code> for
mapping with state.  It yields a sequence of sub-folds over <var>proc</var>.
</p>
<p>The <var>proc</var> argument is a procedure that takes as many arguments
as the input generators plus one.  It is called as
<code>(proc </code><var>v<sub>1</sub> v<sub>2</sub> &hellip; seed)</var>,
where <var>v<sub>1</sub></var>, <var>v<sub>2</sub></var>, &hellip; are
the values yielded from the input generators, and <var>seed</var> is the
current seed value.  It must return two values, the yielding value
and the next seed.
</p>
<p>Note: This differs from <code>generator-fold</code>,
which consumes all
values while folding over them, while <code>gfold/code>
returns a generator immediately without consuming input.
</p></dd></dl>

<dl>
<dt><code>gfilter</code><i> pred gen</i></dt>
<dt><code>gremove</code><i> pred gen</i></dt>
<dd><p>Returns a generator that yield the items from the source generator,
except those on which <var>pred</var> answers false or true respectively.
</p></dd></dl>

<dl>
<dt><code>gfilter-map</code><i> proc gen gen<sub>2</sub> &hellip;</i></dt>
<dd><p>Works the same as <code>(gfilter values (gmap proc gen gen<sub>2</sub> &hellip;))</code>,
only slightly more efficiently.
</p></dd></dl>

<dl>
<dt><code>gstate-filter</code><i> proc seed gen</i></dt>
<dd><p>This allows stateful filtering of a series.  The <var>proc</var> argument
must be a procedure that takes a value <var>v</var> from the source generator and
a seed value.  It should return two values, a boolean flag and the next
seed value.  If the boolean is true, the generator
yields <var>v</var>.  Otherwise, the generator keeps calling <var>proc</var>,
updating the seed value, until the flag is true
or the source generator is exhausted.
</p>
<p>The following example takes a generator of oscillating values
and yields only values that are greater than their previous value.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(generator-&gt;list
 (gstate-filter (lambda (v s) (values (&lt; s v) v)) 0
                (make-element-generator 1 2 3 2 1 0 1 2 3 2 1 0 1 2 3)))
 &rArr; (1 2 3 1 2 3 1 2 3)
</pre></td></tr></table>
</dd></dl>

<dl>
<dt><code>gbuffer-filter</code><i> proc seed gen</i></dt>
<dd><p>This procedure allows n-to-m mapping between elements in input and output &mdash; 
that is, it can use several input elements to generate
one or more output elements.
</p>
<p>The procedure <var>proc</var> receives the next input element and an accumulated
seed value.  It returns two values: A list of output values, and the next
seed value.  If you need to look at more input to generate
output, you can return an empty list as the first value.
</p>
<p>If the input reaches the end, the output ends when the output of the last call to <var>proc</var>
is exhausted (the last seed value is discarded).
</p>
</dd></dl>

<dl>
<dt><code>gtake</code><i> gen k [ padding ]</i></dt>
<dt><code>gdrop</code><i> gen k</i></dt>
<dd><p>The generator analogues of
<code>take</code> and <code>drop</code>.
<code>Gtake</code> returns a generator that yields (at most) the first <var>k</var> items
of the source generator, while <code>gdrop</code> returns a generator
that skips the first <var>k</var> items of the source generator.
</p>
<p>These won't complain if the source generator is exhausted before generating
<var>k</var> items.  By default, the generator returned by <code>gtake</code>
terminates when the source generator does, but if you provide the <var>padding</var> argument,
then the returned generator will yield <var>k</var> items, using the
<var>padding</var> value to provide the rest.
</p>
</dd></dl>

<dl>
<dt><code>gtake-while</code><i> pred gen</i></dt>
<dt><code>gdrop-while</code><i> pred gen</i></dt>
<dd><p>The generator analogues of <code>take-while</code> and <code>drop-while</code>.  The generator returned
from <code>gtake-while</code> yields items from the source generator
as long as <var>pred</var> returns true for each.  The generator returned
from <code>gdrop-while</code> first reads items from the source generator
while <var>pred</var> returns true for them, then starts yielding items returned by the source.
</p></dd></dl>

<dl>
<dt><code>gslices</code><i> gen k [ padding ]</i></dt>
<dd><p>
This returns a generator that yields a list of <var>k</var> items from
the input generator <var>gen</var> at a time.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(generator-&gt;list (gslices (giota 7) 3))
  &rArr; ((0 1 2) (3 4 5) (6))
</pre></td></tr></table>

<p>The <var>padding</var> argument controls how the end
of input is handled, just like <code>gtake</code>.  When <var>padding</var> is
not provided, the last item from the output generator may not
have <var>k</var> items if the input is too short to fill them, as shown
in the above example.  If <var>padding</var> is present and the input is
too short to complete <var>k</var> items, <var>padding</var> is used
to fill the rest.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(generator-&gt;list (gslices (giota 6) 3 'x))
  &rArr; ((0 1 2) (3 4 5))
(generator-&gt;list (gslices (giota 7) 3 'x))
  &rArr; ((0 1 2) (3 4 5) (6 x x))
</pre></td></tr></table>
</dd></dl>

<dl>
<dt><code>gpairs</code><i> car-gen cdr-gen</i></dt>
<dd><p>Returns a generator that yields pairs
whose car is generated from <var>car-gen</var>
and whose cdr is generated from <var>cdr-gen</var>.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">
(define g
  (gpairs (make-generator 113 101 12 68 -55)
          (make-generator #t #f #t #f #f))

(generator-&gt;list g 10)
 &rArr; ((113 . #t) (101 . #f) (12 . #t) (68 . #f) (-55 . #f))
</pre></td></tr></table>
</dd></dl>

<dl>
<dt><code>gtuple</code><i> gen &hellip;</i></dt>
<dd><p>Returns a generator that yields lists 
whose i-th element is generated from the i-th argument.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">
(define g
  (gtuples (make-generator -43 53 -114)
           (make-generator #f #f #f)
           (make-generator #\8 #\1 #\i))

(generator-&gt;list g 3)
 &rArr; ((-43 #f #\8) (53 #f #\1) (-114 #f #\i))
</pre></td></tr></table>
</dd></dl>

<dl>
<dt><code>glists</code><i> sizer item-gen</i></dt>
<dt><code>gvectors</code><i> sizer item-gen</i></dt>
<dt><code>gstrings</code><i> sizer item-gen</i></dt>
<dd><p>Creates a generator that generates lists, vectors or strings of values from <var>item-gen</var>, respectively.  The size of each datum is determined by
<var>sizer</var>, which can
be either a nonnegative integer or a generator of nonnegative integers.
The value of the sizer determines the length of the result data.
</p>
</dl>

<dl>
<dt><code>gdelete</code><i> item gen [ = ]</i></dt>
<dd><p>Creates a generator that returns whatever <var>gen</var> returns, except for any items that
are the same as <var>item</var> in the sense of <var>=</var>, which defaults to <code>equal?</code>.
</p>
</dl>

<dl>
<dt><code>gdelete-neighbor-dups</code><i>gen [ = ]</i></dt>
<dd><p>Creates a generator that returns whatever <var>gen</var> returns, except for any items
that are equal to the preceding item in the sense of <var>=</var>, which defaults to <code>equal?</code>.
</p>
</dl>

<h3 class="subsection">Consuming generated values</h3>

<p>Unless otherwise noted,
these procedures consume all the values of the generator passed to them.  They
have names prefixed with <code>generator-</code>.
</p>

<dl>
<dt><code>generator-&gt;list</code><i> generator [ k ]</i></dt>
<dd><p>Reads items from <var>generator</var> and returns a list of them.
By default, it reads until the generator is exhausted.  If
an optional argument <var>k</var> is given, it must be a nonnegative
integer, and the list ends when either <var>k</var> items are consumed,
or the generator is exhausted.
</p>
<p>Be careful not to pass an infinite generator to this procedure without
specifying <var>k</var>, or this procedure will not return.
</p></dd></dl>

<dl>
<dt><code>generator-&gt;reverse-list</code><i> generator [ k ]</i></dt>
<dd><p>Reads items from <var>generator</var> and returns a list of them in reverse order.
By default, this reads until the generator is exhausted.  If
an optional argument <var>k</var> is given, it must be a nonnegative
integer, and the list ends when either <var>k</var> items are read,
or the generator is exhausted.
</p>
<p>Be careful not to pass an infinite generator to this procedure without
specifying <var>k</var>, or this procedure will not return.
</p></dd></dl>

<dl>
<dt><code>generator-fold</code><i> proc seed gen gen<sub>2</sub> &hellip;</i></dt>
<dd><p>Works like <code>fold</code> on the values generated by the generator
arguments.
</p>
<p>When one generator is given, for each value <var>v</var> generated by <var>gen</var>,
<var>proc</var> is called as <code>(<var>proc</var> <var>v</var> <var>r</var>)</code>, where
<var>r</var> is the current accumulated result; the initial value of the
accumulated result is <var>seed</var>,
and the return value from <var>proc</var> becomes the next accumulated result.
When <var>gen</var> returns an end-of-file object, the accumulated result at that time is returned
from <code>generator-fold</code>.
</p>
<p>When more than one generator is given, <var>proc</var> is
invoked on the values returned by all the generator arguments followed by
the current accumulated result.  The iteration terminates when
any of the generators returns an end-of-file object.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(with-input-from-string &quot;a b c d e&quot;
  (lambda () (generator-fold cons 'z read)))
  &rArr; (e d c b a . z)
</pre></td></tr></table>
</dd></dl>

<dl>
<dt><code>generator-for-each</code><i> proc gen gen<sub>2</sub> &hellip;</i></dt>
<dd><p>A generator analogue of <code>for-each</code> that consumes generated values using side effects.
Repeatedly applies <var>proc</var> on
the values yielded by <var>gen</var>, <var>gen<sub>2</sub></var> &hellip; until any one of
the generators yields an end-of-file object.  The values returned from <var>proc</var> are discarded.
</p></dd></dl>

<dl>
<dt><code>generator-collect</code><i> proc gen gen<sub>2</sub> &hellip;</i></dt>
<dd><p>A generator analogue of <code>map</code>.  Repeatedly applies <var>proc</var> on
the values yielded by <var>gen</var>, <var>gen<sub>2</sub></var> &hellip; until any one of
the generators yields an end-of-file object.   The values returned from <var>proc</var>
are collected into a list and returned.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(with-input-from-string &quot;a b c d e&quot;
  ((lambda () (generator-map symbol-&gt;string read)))
  &rArr; (&quot;a&quot; &quot;b&quot; &quot;c&quot; &quot;d&quot; &quot;e&quot;)
</pre></td></tr></table>

<p>The same effects can be achieved by combining <code>generator-&gt;list</code>
and <code>gmap</code>.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(generator-&gt;list (gmap proc gen gen<sub>2</sub> &hellip;))
</pre></td></tr></table>
</dd></dl>

<dl>
<dt><code>generator-last</code><i> gen</i></dt>
<dd><p>Returns the last item from the generator.
</p></dd></dl>

<dl>
<dt><code>generator-find</code><i> pred gen</i></dt>
<dd><p>Returns the first item from the generator <var>gen</var> that satisfies
the predicate <var>pred</var>.
</p></dd></dl>

<dl>
<dt><code>generator-length</code><i> gen</i></dt>
<dd><p>Returns the number of items available from the generator <var>gen</var>.
</p></dd></dl>

<dl>
<dt><code>generator-count</code><i> pred gen</i></dt>
<dd><p>Returns the number of items available from the generator <var>gen</var> that satisfy
the predicate <var>pred</var>.
</p></dd></dl>

<dl>
<dt><code>generator-any</code><i> pred gen</i></dt>
<dd><p>Returns <code>#t</code> if any of the values available from the generator <var>gen</var> satisfy
the predicate <var>pred</var>.  After such a value is found, the procedure returns without consuming
the rest of the generator.
</p></dd></dl>

<dl>
<dt><code>generator-every</code><i> pred gen</i></dt>
<dd><p>Returns <code>#t</code> if any of the values available from the generator <var>gen</var> do not satisfy
the predicate <var>pred</var>.  After such a value is found, the procedure returns without consuming
the rest of the generator.
</p></dd></dl>

<dl>
<dt><code>generator=?</code><i> pred gen ...</i></dt>
<dd><p>Returns <code>#f</code> if the corresponding values available from the generators <var>gen</var>
are not equal in the sense of the predicate <var>pred</var>.  After such a value is found, the procedure
returns without consuming the rest of the generators.  If all the values of all the generators have been
consumed without finding any values that are not equal, <code>generator=?</code> returns <code>#t</code>.
</p></dd></dl>

<dl>
<dt><code>generator-unfold</code><i> gen unfold arg ...</i></dt>
<dd><p>Equivalent to <code>(</code><var>unfold</var> <code>eof-object? (lambda (x) x)</code> <var>gen</var>
<code>(</code><var>gen</var><code>)</code> <var>args</var> ...<code>)</code>.  The values of <var>gen</var>
are unfolded into the collection that <var>unfold</var> creates.  The combination of <code>make-for-each-generator</code> and <code>generator-unfold</code> makes it possible to convert any collection
that has a for-each procedure into any collection that has an unfold constructor.
</p></dd></dl>

<h3 class="subsection">Syntax</h3>

<dl>
<dt><code>generator-let*</code><i> (binding &hellip;) body body2 &hellip;</i></dt>
<dd><p>This captures a monadic pattern that frequently appears in generator-related
code.  It is similar in spirit to <code>and-let*</code> from SRFI 2, but returns
as soon as an evaluated expression returns an end-of-file object.
</p>
<p>The <var>binding</var> part can be either <code>(var expr)</code> or <code>( expr )</code>.
The actual definition will explain this syntax clearly.
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(define-syntax generator-let*
  (syntax-rules ()
    ((_ () body body2 ...) (begin body body2 ...))
    ((_ ((var gen-expr) more-bindings ...) . body)
     (let ((var gen-expr))
       (if (eof-object? var)
         var
         (generator-let* (more-bindings ...) . body))))
    ((_ (( gen-expr ) more-bindings ...) . body)
     (let ((var gen-expr))
       (if (eof-object? var)
         var
         (generator-let* (more-bindings ...) . body))))))
</pre></td></tr></table>
</dd></dl>

<dl>
<dt><code>do-generator</code><i> (var gexpr) body &hellip;</i></dt>
<dd>
<p><var>Gexpr</var> is an expression that yields a generator.  It is
evaluated once.  The resulting generator is called repeatedly
until it returns an end-of-file object.  Every time the generator is called,
the <var>body</var> expressions are evaluated in a scope
where <var>var</var> is bound to the value returned from the generator.
</p>
<p>This macro exists for performing
side-effects.  You can do the same thing with <code>generator-for-each</code>,
but sometimes this macro makes the imperative code more readable:
</p>
<table><tr><td>&nbsp;</td><td><pre class="example">(do-generator (line read-line)
  ;; do some side-effecting stuff with line
  )
</pre></td></tr></table>
</dd></dl>
}}}

time

2014-10-20 07:13:31

version

13