summaryrefslogtreecommitdiff
path: root/devdocs/elisp/generators.html
blob: 24646221fddf86409b76765a55ccf14afec6b95c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 <h3 class="section">Generators</h3>  <p>A <em>generator</em> is a function that produces a potentially-infinite stream of values. Each time the function produces a value, it suspends itself and waits for a caller to request the next value. </p> <dl> <dt id="iter-defun">Macro: <strong>iter-defun</strong> <em>name args [doc] [declare] [interactive] body…</em>
</dt> <dd>
<p><code>iter-defun</code> defines a generator function. A generator function has the same signature as a normal function, but works differently. Instead of executing <var>body</var> when called, a generator function returns an iterator object. That iterator runs <var>body</var> to generate values, emitting a value and pausing where <code>iter-yield</code> or <code>iter-yield-from</code> appears. When <var>body</var> returns normally, <code>iter-next</code> signals <code>iter-end-of-sequence</code> with <var>body</var>’s result as its condition data. </p> <p>Any kind of Lisp code is valid inside <var>body</var>, but <code>iter-yield</code> and <code>iter-yield-from</code> cannot appear inside <code>unwind-protect</code> forms. </p> </dd>
</dl> <dl> <dt id="iter-lambda">Macro: <strong>iter-lambda</strong> <em>args [doc] [interactive] body…</em>
</dt> <dd><p><code>iter-lambda</code> produces an unnamed generator function that works just like a generator function produced with <code>iter-defun</code>. </p></dd>
</dl> <dl> <dt id="iter-yield">Macro: <strong>iter-yield</strong> <em>value</em>
</dt> <dd><p>When it appears inside a generator function, <code>iter-yield</code> indicates that the current iterator should pause and return <var>value</var> from <code>iter-next</code>. <code>iter-yield</code> evaluates to the <code>value</code> parameter of next call to <code>iter-next</code>. </p></dd>
</dl> <dl> <dt id="iter-yield-from">Macro: <strong>iter-yield-from</strong> <em>iterator</em>
</dt> <dd><p><code>iter-yield-from</code> yields all the values that <var>iterator</var> produces and evaluates to the value that <var>iterator</var>’s generator function returns normally. While it has control, <var>iterator</var> receives values sent to the iterator using <code>iter-next</code>. </p></dd>
</dl> <p>To use a generator function, first call it normally, producing a <em>iterator</em> object. An iterator is a specific instance of a generator. Then use <code>iter-next</code> to retrieve values from this iterator. When there are no more values to pull from an iterator, <code>iter-next</code> raises an <code>iter-end-of-sequence</code> condition with the iterator’s final value. </p> <p>It’s important to note that generator function bodies only execute inside calls to <code>iter-next</code>. A call to a function defined with <code>iter-defun</code> produces an iterator; you must drive this iterator with <code>iter-next</code> for anything interesting to happen. Each call to a generator function produces a <em>different</em> iterator, each with its own state. </p> <dl> <dt id="iter-next">Function: <strong>iter-next</strong> <em>iterator value</em>
</dt> <dd>
<p>Retrieve the next value from <var>iterator</var>. If there are no more values to be generated (because <var>iterator</var>’s generator function returned), <code>iter-next</code> signals the <code>iter-end-of-sequence</code> condition; the data value associated with this condition is the value with which <var>iterator</var>’s generator function returned. </p> <p><var>value</var> is sent into the iterator and becomes the value to which <code>iter-yield</code> evaluates. <var>value</var> is ignored for the first <code>iter-next</code> call to a given iterator, since at the start of <var>iterator</var>’s generator function, the generator function is not evaluating any <code>iter-yield</code> form. </p>
</dd>
</dl> <dl> <dt id="iter-close">Function: <strong>iter-close</strong> <em>iterator</em>
</dt> <dd><p>If <var>iterator</var> is suspended inside an <code>unwind-protect</code>’s <code>bodyform</code> and becomes unreachable, Emacs will eventually run unwind handlers after a garbage collection pass. (Note that <code>iter-yield</code> is illegal inside an <code>unwind-protect</code>’s <code>unwindforms</code>.) To ensure that these handlers are run before then, use <code>iter-close</code>. </p></dd>
</dl> <p>Some convenience functions are provided to make working with iterators easier: </p> <dl> <dt id="iter-do">Macro: <strong>iter-do</strong> <em>(var iterator) body …</em>
</dt> <dd><p>Run <var>body</var> with <var>var</var> bound to each value that <var>iterator</var> produces. </p></dd>
</dl> <p>The Common Lisp loop facility also contains features for working with iterators. See <a href="https://www.gnu.org/software/emacs/manual/html_node/cl/Loop-Facility.html#Loop-Facility">Loop Facility</a> in <cite>Common Lisp Extensions</cite>. </p> <p>The following piece of code demonstrates some important principles of working with iterators. </p> <div class="example"> <pre class="example">(require 'generator)
(iter-defun my-iter (x)
  (iter-yield (1+ (iter-yield (1+ x))))
   ;; Return normally
  -1)

(let* ((iter (my-iter 5))
       (iter2 (my-iter 0)))
  ;; Prints 6
  (print (iter-next iter))
  ;; Prints 9
  (print (iter-next iter 8))
  ;; Prints 1; iter and iter2 have distinct states
  (print (iter-next iter2 nil))

  ;; We expect the iter sequence to end now
  (condition-case x
      (iter-next iter)
    (iter-end-of-sequence
      ;; Prints -1, which my-iter returned normally
      (print (cdr x)))))
</pre>
</div><div class="_attribution">
  <p class="_attribution-p">
    Copyright &copy; 1990-1996, 1998-2022 Free Software Foundation, Inc. <br>Licensed under the GNU GPL license.<br>
    <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Generators.html" class="_attribution-link">https://www.gnu.org/software/emacs/manual/html_node/elisp/Generators.html</a>
  </p>
</div>