<?xml version="1.0" encoding="utf-8"?><article xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-subset Balisage-1.5" xml:id="HR-23632987-8973">
  <title>Generators - Deferred Evaluation in XPath 4</title>
  <info>
    <confgroup>
      <conftitle>Balisage: The Markup Conference 2026</conftitle>
      <confdates>August 3-7, 2026</confdates>
   </confgroup> 
    <abstract>
      <para>XPath lacks an explicitly-specified portable mechanism for processing large, unbounded, 
            or externally sourced data without full materialization. The paper addresses this limitation 
            by introducing generators as a first-class abstraction for deferred evaluation in XPath 4.</para>
        <para>Generators are represented as immutable records that encapsulate state 
             and two operations—value access and progression—allowing result-values 
             to be computed incrementally and only when demanded. 
             On top of this abstraction, the paper defines a composable library of functions 
             that enables complex data-processing pipelines without eager evaluation.</para>
        <para>This model provides:        
         <itemizedlist>
			        <listitem>
			          <para>precise control over evaluation,</para>
			        </listitem>
			        <listitem>
			          <para>natural support for infinite and streaming data,</para>
			        </listitem>
			        <listitem>
			          <para>early termination without special constructs, and</para>
			        </listitem>
			        <listitem>
			          <para>integration with external data sources via a precisely-defined provider protocol.</para>
			        </listitem>
      </itemizedlist>
        </para>
        <para>
	        The approach is entirely implementation-independent and is expressed 
	        using executable XPath definitions. Through examples and a real-world use case of news feed aggregation, 
	        the paper demonstrates how generators extend XPath with a practical and expressive model 
	        for resource-efficient computation.
        </para>
    </abstract>
    <author>
      <personname>
        <firstname>Dimitre</firstname>
        <surname>Novatchev</surname>
      </personname>
      <personblurb><para/></personblurb>
      <email>dnovatchev@gmail.com</email>
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://dnovatchev.wordpress.com/</link>
    </author>
    <legalnotice><para>Copyright: Dimitre Novatchev, 2026</para></legalnotice>
    <keywordset role="author">
      <keyword>XPath</keyword>
      <keyword>Deferred Evaluation</keyword>
      <keyword>Generators</keyword>
    </keywordset>
  </info>
  <section xml:id="dngen1">
    <title>1.	The Problem</title>
    <para>In some cases we need to generate or process a huge, potentially unlimited number of XPath [<xref linkend="xpath-31"/>] items 
         and sequences, referred here as collection of values or simply collection. Typically, not all of these 
         may be needed at a specific point  of the evaluation. There are at least two issues that we need 
         to address:
         <informaltable>
           <tr>
             <td>A.</td>
             <td>We are not sure of the amount of memory that would be needed to contain the collection. 
                 We would like only the next member of the collection to be “materialized” and provided 
                 only on demand, when we actually need it.
             </td>
           </tr>
           <tr>
             <td>B.</td>
             <td>Even if issue A. was not present, and we are confident that all members of the collection 
                 can be contained in memory, how do we ensure the early exit from processing 
                 and not continuing to obtain/generate and traverse all members of the collection? 
                 Ideally, the caller should be empowered 
                 so that they may only issue the minimum necessary number of requests to meet 
                 their processing requirements.
             </td>
           </tr>
         </informaltable>
    </para>
    <para>
      It is also possible to foresee a potential third issue, 
      where the caller needs to be able to dynamically define a short-circuiting strategy [<xref linkend="lazy-xpath"/>]
      to prevent from hanging an aggregating operation; such as folding, over an infinite collection of members.
     
      One can argue that different vendors of XPath processors already provide some mechanisms 
      to some of these issues. Unfortunately, such solutions [<xref linkend="saxon-lazy"/>] are limited, 
      incomplete, and vary from one vendor to the other (<emphasis role="ital">See</emphasis> <xref linkend="dngen-app1"/>.), 
      which results in confusion for the XPath programmer, 
      and vendor dependency and lock-in. More critically, as such solutions are not required 
      by the XPath standard, nothing prevents a vendor from removing such a mechanism 
      from their product and thus breaking invisibly a user’s existing XPath code. 
    </para>
    <para>
      <emphasis role="bold">
      In contrast, we need a solution that is implementation-independent 
      and that puts us – the XPath programmers in full control.
      </emphasis>
    </para>
  </section>
  <section xml:id="dngen2">
    <title>2. The Solution - Generators</title>
    <para>The solution we propose to these issues is based on the concept of <emphasis role="ital">Generators</emphasis>.</para>
    <para><emphasis role="ital">Generators</emphasis> [<xref linkend="gen-wiki"/>] are wellknown 
         and integrated within many programming languages. Per Wikipedia:</para>
    <para>“<emphasis role="ital">In computer science, a generator is a routine that can be used to control 
           the iteration behaviour of a loop. All generators are also iterators. 
           A generator is very similar to a function that returns an array, 
           in that a generator has parameters, can be called, and generates a sequence of values.
           However, instead of building an array containing all the values and returning them all at once, 
           a generator yields the values one at a time, which requires less memory and allows the caller 
           to get started processing the first few values immediately. 
           In short, a generator looks like a function but behaves like an iterator.”
           </emphasis>
   </para>
     <section xml:id="dngen2-1">
       <title>2.1 The Generator Record</title>
       <para>
        We define the Generator record 
          <footnote xml:id="dngen-f1">
           <para>
          The record type has been introduced in XPath 4 and may undergo changes in its semantics. 
          The author will update the text of the article and the executable, 
          formal definitions if new changes in the generator type are introduced.</para></footnote> 
        in the following way:
<programlisting language="xquery" xml:space="preserve">
declare namespace f = "http://www.w3.org/2005/xpath-functions-2025";
declare record f:generator 
   ( initialized as xs:boolean,
     end-reached as xs:boolean,
     get-current as fn($this as f:generator) as item()*,
     move-next as   fn($this as f:generator) as f:generator,           
     state as map(*)
   );        
</programlisting>
       </para>
       <para>The <emphasis role="bital">f:generator</emphasis> record has 5 fields, two of which are methods.</para>
       <para>
         Procedural languages and XPath differ fundamentally in their treatment of state. 
         In a procedural language, a variable's value can change during execution. 
         XPath variables, however, are immutable.
         Therefore, what would be represented as a single state-changing generator object in a procedural language 
         must be represented in XPath as a sequence of generator <emphasis role="ital">instances</emphasis>. 
         Each instance corresponds to exactly one state.

         Note that the sequence of generator instances produced by consecutively applying the  
         <emphasis role="ital">move-next</emphasis> method can be finite, ending with a final generator instance, 
         or it could be <emphasis role="ital">infinite</emphasis> and have no such a final generator instance.
       </para>
       <para>
          <itemizedlist>
			        <listitem>
			          <para><emphasis role="bold">get-current</emphasis></para>
			          <para>Normally, the value associated with a given generator instance is obtained 
			                by calling the  <emphasis role="ital">get-current</emphasis>  method. 
			                If the current generator instance is the final generation instance, 
			                or is not initialized (see below), <emphasis role="ital">get-current</emphasis>  raises an error.
               </para>
			        </listitem>
			        <listitem>
			          <para><emphasis role="bold">move-next</emphasis></para>
			          <para>Normally, the method <emphasis role="ital">move-next</emphasis> produces the next generator 
			                instance and calling the <emphasis role="ital">get-current</emphasis>  method  
			                on this next generation instance produces the value represented in this  next-generation instance. 
			                If the current generator instance is the final generation instance (see below), 
			                <emphasis role="ital">move-next</emphasis>  raises an error.
               </para>
			        </listitem>
			        <listitem>
			          <para><emphasis role="bold">state</emphasis></para>
			          <para>This map contains all key-value map-entries that are necessary for the work of the two methods: 
			                <emphasis role="ital">get-current</emphasis> and <emphasis role="ital">move-next</emphasis>.
               </para>
			        </listitem>
			        <listitem>
			          <para><emphasis role="bold">initialized</emphasis></para>
			          <para>The <emphasis role="ital">initialized</emphasis> flag 
                      allows generators to defer computation of the first value. 
			                A generator instance having <code>initialized eq false()</code> must be advanced via 
			                <emphasis role="ital">move-next</emphasis> before a value can be retrieved.
               </para>
               <para><emphasis role="bold">Note</emphasis>:  trying to evaluate  <emphasis role="ital">get-current</emphasis> 
                     on a non-initialized generator instance (having <code>initialized eq false()</code>) raises an error.
               </para>
			        </listitem>
			        <listitem>
			          <para><emphasis role="bold">end-reached</emphasis></para>
			          <para>If the sequence of generator instances produced by consecutively applying the  <emphasis role="ital">move-next</emphasis> method 
			                is a finite one, the final generator instance has no associated value.</para>
			          <para>
                    The boolean field <emphasis role="ital">end-reached</emphasis>
                    is used to indicate  that this is the final generator instance, having no value 
                    and not allowing to produce a next generator instance by applying on it the method  
                    <emphasis role="ital">move-next</emphasis>. Thus, by definition, <emphasis role="ital">end-reached</emphasis> is 
                    <code>true()</code> only on the final generator instance, and <code>false()</code> on all other, 
                    non-final, generator instances.
               </para>
               <para><emphasis role="bold">Note</emphasis>:  trying to evaluate  <emphasis role="ital">get-current</emphasis>
                     or <emphasis role="ital">move-next</emphasis> 
                     upon the final (empty) generator raises an error.
               </para>
			        </listitem>
      </itemizedlist>      
       </para>
     </section>
     <section xml:id="dngen2-2">
       <title>2.2 Definitions</title>
       <para><emphasis role="bold">Definition1</emphasis>: <emphasis role="ital">Empty generator</emphasis>: Any generator
             instance whose <emphasis role="ital">end-reached</emphasis> value is <code>true()</code>.
       </para>
       <para><emphasis role="bold">Definition2</emphasis>: <emphasis role="ital">Yield of a generator</emphasis>.
       </para>
       <para>
        Starting from an initialized generator instance <emphasis role="bital">G<subscript>1</subscript></emphasis>, 
        repeated application of <emphasis role="ital">move-next</emphasis> produces 
        a sequence of generator instances <emphasis role="bital">G<subscript>2</subscript></emphasis>, 
        <emphasis role="bital">G<subscript>3</subscript></emphasis>, …, <emphasis role="bital">G<subscript>n</subscript></emphasis>, …
       </para>
       <para>
         The <emphasis role="bold">yield</emphasis> of the generator is the sequence of values obtained by applying 
         <emphasis role="ital">get-current</emphasis> to each of these instances, until an instance with 
         <code>end-reached eq true()</code> is encountered (or indefinitely, for infinite generators).
       </para>
       <para>
         <emphasis role="bold">Note</emphasis>: The yield is empty, 
         if $<emphasis role="bital">G<subscript>1</subscript></emphasis><code>?end-reached eq true()</code> 
         and the yield is infinite if neither 
         $<emphasis role="bital">G<subscript>1</subscript></emphasis><code>?end-reached eq true()</code>
         nor any of the consecutive applications of  <emphasis role="ital">move-next</emphasis> produces 
         a generator-instance $<emphasis role="bital">G<subscript>x</subscript></emphasis>, such that 
         $<emphasis role="bital">G<subscript>x</subscript></emphasis><code>?end-reached eq true()</code> .
       </para>
     </section>
     <section xml:id="dngen2-3">
       <title>2.3 Examples</title>
       <para><emphasis role="bold">Example1</emphasis>:</para>
       <para>
        Given this example XML document:
<programlisting language="xml" xml:space="preserve">
&lt;x&gt;
   &lt;y&gt;
      &lt;z/&gt;
   &lt;/y&gt;
&lt;/x&gt;
</programlisting>       
       </para>
       <para>
         Below is a generator that will yield the names of the first in document-order leaf-node in the XML document and of its consecutive ancestors, 
         with `\` as the “name” of the <code>document-node()</code>:
<programlisting language="xpath" xml:space="preserve">
let $genLeafAndAncestorNames := 
   f:generator(initialized := true(), 
               end-reached := false(), 
               get-current :=  fn($this as f:generator) 
                                { let $current := $this?state?currentNode  
                                  return 
                                   if($current instance of document-node()) then '/'
                                      else $current/name()                                
                                },
               move-next := fn($this as f:generator)
                            {
                              if(empty($this?state?currentNode/..))                                                      
                                then map:put($this, "end-reached", true())    
                                else map:put($this, "state", 
                                             map{"currentNode": $this?state?currentNode/..})                                                      
                            },
               state := map{"currentNode" : 
                                    (parse-xml(
                                      '&lt;x&gt;
                                         &lt;y&gt;
                                            &lt;z/&gt;
                                         &lt;/y&gt;                                                                        
                                       &lt;/x&gt;')//*[not(*)]
                                     )[1]
                            }         
</programlisting>
          <emphasis role="ital"><code>$genLeafAndAncestorNames</code></emphasis> is a generator-instance with a finite yield. 
          This yield is the ordered collection of values – the names of the first in document order leaf node 
          and its ancestor-nodes: "z", "y", "x", / .
       </para>
       <para><emphasis role="bold">Example2</emphasis>:</para>
       <para>
<programlisting language="xpath" xml:space="preserve">
$genFibo := f:generator(initialized := true(), end-reached := false(),
                        get-current := fn($this as f:generator) 
                                         {$this?state?current},
                        move-next := fn($this as f:generator)
                                     {map:put($this, "state", 
                                              map{"current": $this?state?next,
                                                  "next": $this?state?current 
                                                         + $this?state?next}
                                              )},
                        state := map{"current": 0, "next": 1}
                       )
</programlisting>
         <emphasis role="ital"><code>$genFibo</code></emphasis> is a generator-instance with an infinite yield. 
         This yield is the ordered collection of the numbers comprising the Fibonacci sequence [<xref linkend="fibo-wiki"/>]: 
         <code>0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …, …</code>                       
       </para>
     </section>
  </section>
  <section xml:id="dngen3">
    <title>3. Functions on Generators</title>
    <para>
     The functions defined in this section can be referenced with a conventional namespace prefix 
     "gn", which is bound to the namespace URI  “<emphasis role="ital">http://www.w3.org/2005/xpath-functions/generator</emphasis>”. 
     They are listed under the following categories, based on the type of the function result:
     <informaltable>
       <tr>
         <td>a.</td>
         <td>Functions returning a specific yield-value: an <code>item()</code> or a sequence.</td> 
       </tr>
       <tr>
         <td>b.</td>
         <td>Functions that produce another generator from existing generators.</td> 
       </tr>
       <tr>
         <td>c.</td>
         <td>Functions that produce a generator from data by a data-provider.</td> 
       </tr>
       <tr>
         <td>d.</td>
         <td>Functions that completely materialize the yield of a generator as an XPath array, sequence, or map.</td> 
       </tr>
     </informaltable>
    </para>
    <para>
     The functions in group a., b., and c. (above) do not eagerly evaluate  the yield of any of their generator-arguments. 
     A single value from a yield is produced only if explicitly requested by evaluating the methods 
     <emphasis role="ital">move-next</emphasis> and <emphasis role="ital">get-current</emphasis>. At no point in the computation 
     is it necessary to have all values of a yield available. In most cases, at any point in the evaluation, a function would only need 
     one or possibly a few values to be yielded. No unnecessary computation of a value from a yield is done and no memory is used 
     to hold such unnecessary values at any point in the computation. 
     This is why the evaluation of the functions defined here is referred to as "<emphasis role="bold">Deferred Evaluation</emphasis>".
    </para>
    <para>
      The functions in group <emphasis role="bold">a</emphasis>. (above) return a single yield value – an <code>item()</code> or an XPath sequence - that may be the result 
      of a query or aggregation.
    </para>
    <para>
      Any function from group <emphasis role="bold">b</emphasis>. (above) takes a generator as its first argument and returns a generator. 
      This allows the <emphasis role="bold">chaining of function calls</emphasis> to produce a generator whose yield is a complex transformation 
      of the yields of the generators that are supplied as arguments.
    </para>
    <para>
      The functions in group <emphasis role="bold">c</emphasis>. (above) produce a generator whose yield is comprised of the values 
      supplied by an <emphasis role="ital">external data provider</emphasis>. An external data provider is a function that communicates 
      with its caller via strictly defined contract around its argument and its return value. 
      The user can define their own external data providers for any desired data source, such as a file, a database, a web-service, …, etc.
    </para>
    <para>
      The functions in group <emphasis role="bold">d</emphasis>. (above) materialize the complete yield of the provided generator 
      and are provided as a convenience to assist the user in debugging or testing their code.
      </para>
    <para>      
       Next we briefly describe the functions from each of these four groups. 
       Complete and executable XPath/XQuery 4.0 formal definitions are provided on the author’s Github [<xref linkend="gen-formal"/>].
    </para>
    <section xml:id="dngen3-1">
      <title>3.1 Functions returning a specific value: an XPath <code>item()</code> or a sequence</title>
      <para>
        This group of functions returns a single value based on the yield of a supplied generator. 
        Each function inspects the yield only as far as necessary to obtain that value:
        
        <table rules="rows" frame="void">
          <caption><para>Functions returning a specific value</para></caption>
          <thead>
            <tr><th><emphasis role="bold">Function</emphasis></th> 
                <th><emphasis role="bold">Meaning</emphasis></th></tr>
          </thead>
	        <tbody>
	          <tr>
	            <td><code>gn:at</code></td>
	            <td>Returns the <code>$k</code>-th value from the yield of the <code>$generator</code></td>
	          </tr>
	          <tr>
	            <td><code>gn:contains</code></td>
	            <td>Returns <code>true()</code> if the <code>$value</code> is contained in the yield of the generator, 
	               and <code>false()</code> otherwise. The comparisons are done using <code>fn:deep-equal</code>.</td>
	          </tr>
	          <tr>
	            <td><code>gn:first-where</code></td>
	            <td>Returns the first <code>$value</code> in the yield of the generator for which 
	            <code>$predicate($value)</code> is <code>true()</code>. If the generator's yield doesn't contain any such item, an error is raised.</td>
	          </tr>
	          <tr>
	            <td><code>gn:fold-left</code></td>
	            <td>Processes consecutively the values of the yield of the supplied generator, 
	                applying the supplied function repeatedly to each value in turn, together with an accumulated result value.</td>
	          </tr>
	          <tr>
	            <td><code>gn:fold-right</code></td>
	            <td>Processes consecutively from right-to-left the values of the yield of the supplied generator, 
	                applying the supplied function repeatedly to each value in turn, together with an accumulated result value.</td>
	          </tr>
	          <tr>
	            <td><code>gn:fold-lazy</code></td>
	            <td>Produces the same result as <code>gn:fold-right</code> on the entire yield of the <code>$generator</code> 
	            with the operation specified by <code>$action</code> but also performs short-circuiting 
	            if detected by the supplied <code>$short-circuit-detector</code> function.</td>
	          </tr>
	          <tr>
	            <td><code>gn:head</code></td>
	            <td>Produces the first value contained in the yield of the <code>$generator</code></td>
	          </tr>
	          <tr>
	            <td><code>gn:some</code></td>
	            <td>Returns <code>true()</code> if and only if the generator is initialized and its yield contains at least one value.</td>
	          </tr>
	          <tr>
	            <td><code>gn:some-where</code></td>
	            <td>Returns <code>true()</code> if the generator is initialized and its yield contains any value 
	            upon which evaluating the supplied <code>$predicate</code> returns <code>true()</code>. Otherwise, <code>false()</code> is returned.</td>
	          </tr>
	          <tr>
	            <td><code>gn:value</code></td>
	            <td>Produces the value contained in this generator-instance.</td>
	          </tr>
	        </tbody>
        </table>        
      </para>
    </section>
    <section xml:id="dngen3-2">
      <title>3.2	Functions that produce another generator from existing generators</title>
      <para>
        Any function in this group takes a generator as its first argument and returns a generator. 
        This allows <emphasis role="bold">chaining of function calls</emphasis> to produce a generator 
        whose yield is a complex transformation of the yields of the generators that are supplied as arguments.
        <table rules="rows" frame="void">
         <caption><para>Functions that produce another generator from existing generators</para></caption>
	        <thead>
	            <tr><th><emphasis role="bold">Function</emphasis></th> <th><emphasis role="bold">Meaning</emphasis></th></tr>
	        </thead>
		      <tbody>
	          <tr>
	            <td><code>gn:chunk</code></td>
	            <td>Returns a new generator each of whose yield values is a "chunk" of consecutive values 
	               of the yield of the supplied <code>$generator</code> held in an array of size <code>$size</code>, 
	               with the possible exception that the size of the array containing the last "chunk" could be smaller.</td>
	          </tr>		        
	          <tr>
	            <td><code>gn:concat</code></td>
	            <td>Returns a new generator whose yield consists of the yield of <code>$generator</code> followed by the yield 
	               of <code>$generator2</code>.</td>
	          </tr>		        
	          <tr>
	            <td><code>gn:distinct</code></td>
	            <td>Returns a new generator whose yield contains only the distinct values from the original generator, in their original order.</td>
	          </tr>		        
	          <tr>
	            <td><code>gn:filter</code></td>
	            <td>Returns a new generator whose yield contains exactly those values from the yield of the original generator, 
	                upon which the supplied predicate returns <code>true()</code>, in their original order.</td>
	          </tr>		        
	          <tr>
	            <td><code>gn:for-each</code></td>
	            <td>Produces a new generator, in the yield of which each value is the result of applying the function item 
	                <code>$action</code> on the corresponding value of the yield of the original <code>$generator</code>, in their original order.</td>
	          </tr>		        
	          <tr>
	            <td><code>gn:for-each-pair</code></td>
	            <td>Produces a new generator, in the yield of which each value is the result of applying the function item 
	                <code>$action</code> on the corresponding values of the yields of <code>$generator1</code> 
	                and <code>$generator2</code>, in their original order.</td>
	          </tr>		        
	          <tr>
	            <td><code>gn:insert-at</code></td>
	            <td>Returns a generator whose yield contains the first <code>$position - 1</code> values of the yield of <code>$generator</code>, 
	                followed by the supplied <code>$value</code>, followed by all the values of the yield of <code>$generator</code>
	                starting from position <code>$position</code>.</td>
	          </tr>		
	          <tr>	                  
	            <td><code>gn:merge-sorted-generators</code></td>
	            <td>Produces a new generator from a generator each of whose yield values is itself a generator that has a yield of sorted values.</td>
	          </tr>		        
	          <tr>
	            <td><code>gn:next</code></td>
	            <td>Produces the next state/generator-instance obtained from the current generator-instance <code>$generator</code>.</td>
	          </tr>		        
	          <tr>
	            <td><code>gn:prepend</code></td>
	            <td>Returns a generator, whose yield is the supplied <code>$value</code> followed by the values of the yield 
	                of the supplied <code>$generator</code>.</td>
	          </tr>		        
	          <tr>
	            <td><code>gn:remove-at</code></td>
	            <td>Returns a generator, whose yield is the result of removing the <code>$position</code><subscript>th</subscript> value 
	                from the yield of the supplied <code>$generator</code>.</td>
	          </tr>		
	          <tr>
	            <td><code>gn:remove-where</code></td>
	            <td>Returns a generator, whose yield is the result of removing from the yield of the supplied <code>$generator</code>
	                all values upon which the supplied <code>$predicate</code> is <code>true()</code>. 
	            </td>
	          </tr>		
	          <tr>
	            <td><code>gn:replace</code></td>
	            <td>Returns a generator, whose yield is the result of replacing in the yield of the supplied <code>$generator</code> 
	               the first value upon which the application of the supplied <code>$predicate</code> returns <code>true()</code>
	               with the supplied <code>$replacement</code>. 
	            </td>
	          </tr>		
	          <tr>
	            <td><code>gn:reverse</code></td>
	            <td>Returns a generator, the values of whose yield are the ones in the yield of the supplied <code>$generator</code> but in reverse order.
	            </td>
	          </tr>		
	          <tr>
	            <td><code>gn:scan-left</code></td>
	            <td>Returns a generator whose yield contains the partial results of the evaluation of the <code>gn:fold-left</code> function with the same arguments. 
	            </td>
	          </tr>		
	          <tr>
	            <td><code>gn:scan-right</code></td>
	            <td>Returns a generator whose yield contains the partial results of the evaluation of the <code>gn:fold-right</code> function with the same arguments. 
	            </td>
	          </tr>		
	          <tr>
	            <td><code>gn:skip</code></td>
	            <td>Returns a generator whose yield contains only the values of the yield of the supplied <code>$generator</code>
	               after the <code>$n</code><subscript>th</subscript> one and in their original order. 
	            </td>
	          </tr>		
	          <tr>
	            <td><code>gn:skip-strict</code></td>
	            <td>Returns a generator whose yield contains only the values of the yield of the supplied <code>$generator</code>
	               after the <code>$n</code><subscript>th</subscript> one and in their original order.
	               If the yield of the supplied <code>$generator</code> contains less than <code>$n</code> values, 
	               and the supplied argument <code>$raise-error-on-empty</code> is <code>true()</code> then an error is raised. 
	            </td>
	          </tr>
	          <tr>
	            <td><code>gn:skip-while</code></td>
	            <td>Returns a new generator whose yield contains all the values from the yield of the supplied <code>$generator</code>, 
	                having removed the longest leading segment of values on which the supplied <code>$predicate</code> returns <code>true()</code>. 
	            </td>
	          </tr>		
	          <tr>
	            <td><code>gn:subrange</code></td>
	            <td>Returns a new generator whose yield contains the values from the yield of the original <code>$generator</code>, 
	            from position <code>$start</code>  to position <code>$end</code> in their original order. 
	            </td>
	          </tr>		
	          <tr>
	            <td><code>gn:tail</code></td>
	            <td>Returns a new generator whose yield contains all the values but the first from the yield of the original <code>$generator</code>
	                or raises an error if the supplied generator's yield is empty. 
	            </td>
	          </tr>		
	          <tr>
	            <td><code>gn:take</code></td>
	            <td>Returns a new generator whose yield is the leading segment with length <code>$n</code> from the yield of the original 
	               <code>$generator</code> or, in case the supplied generator's yield length is not bigger than <code>$n</code>, 
	               then the result is a generator that has exactly the supplied generator's yield. 
	            </td>
	          </tr>		
	          <tr>
	            <td><code>gn:take-while</code></td>
	            <td>Returns a new generator whose yield contains the longest leading segment from the yield of the original <code>$generator</code>
	                on all values of which the provided function <code>$predicate</code>  returns <code>true()</code>. 
	            </td>
	          </tr>		
	          <tr>
	            <td><code>gn:zip</code></td>
	            <td>Returns a new generator the <code>k</code><subscript>th</subscript> value of whose yield is an array having two members: 
	               the <code>k</code><subscript>th</subscript> value of the yield of <code>$generator1</code> 
	               and the <code>k</code><subscript>th</subscript> value of the yield of <code>$generator2</code>, 
	               where <code>k</code> does not exceed the smaller of the lengths of the yields of the two generators. 
	            </td>
	          </tr>			          
		      </tbody>        
        </table>        
      </para>
    </section>
    <section xml:id="dngen3-3">
     <title>3.3	Functions that produce a generator from data provided by a data-provider</title>
     <para>
       The functions in this group construct a generator whose yield is supplied one value at a time 
       by an <emphasis role="bold">external-provider</emphasis> function. Providers allow generators to expose yields that are too large 
       to fit into memory, must be computed incrementally, or require access to external systems (such as files, databases, or web services).
     </para>
     <para>
       A provider function must adhere to a contract with its client (generator) and is responsible for producing, on each invocation, both:
       <orderedlist numeration="arabic">
         <listitem>
           <para>
             <emphasis role="bold">state-data</emphasis> - an array with information required for the provider to compute its next result, and
           </para>
         </listitem>
         <listitem>
           <para>
             <emphasis role="bold">result-data</emphasis> - an array either containing a single yield-value or empty - to signal 
              that the data for producing the yield has been exhausted.
           </para>
         </listitem>
       </orderedlist>
     </para>
     <para>
       The generator returned by these functions behaves identically to any other generator: values are not computed eagerly 
       but are obtained only as result of evaluating the method <emphasis role="ital">get-current</emphasis> 
       on the generator-instance produced by <emphasis role="ital">move-next</emphasis>.
     </para>
     <para>
       There is also an additional function in this group: <code>gn:empty-generator</code>. It simply produces a new generator 
       whose yield does not contain any values and this function hasn’t a data-provider parameter.
        <table rules="rows" frame="void">
         <caption><para>Functions that produce a generator from data provided by a data-provider</para></caption>
	        <thead>
	            <tr><th><emphasis role="bold">Function</emphasis></th> 
                  <th><emphasis role="bold">Meaning</emphasis></th></tr>
	        </thead>
		      <tbody>
	          <tr>
	            <td><code>gn:make-generator</code></td>
	            <td>Returns a generator, the values of whose yield are obtained by consecutive calls 
	                to a supplied <code>$provider</code> function.</td>
	          </tr>	
	          <tr>
	            <td><code>gn:make-generator-from-array</code></td>
	            <td>Returns a generator, the values of whose yield are the values of the supplied  <code>$input</code> array.</td>
	          </tr>	
	          <tr>
	            <td><code>gn:make-generator-from-sequence</code></td>
	            <td>Returns a generator, the values of whose yield are the values of the supplied  <code>$input</code> sequence.</td>
	          </tr>	
	          <tr>
	            <td><code>gn:make-generator-from-map</code></td>
	            <td>Returns a generator, whose yield is the sequence of all single map entries of the supplied <code>$input</code> map.</td>
	          </tr>	
	          <tr>
	            <td><code>gn:empty-generator</code></td>
	            <td>Returns a new generator whose yield does not contain any values.</td>
	          </tr>		          
	       </tbody>	  
	     </table>      
     </para>
    </section>
    <section xml:id="dngen3-4">
     <title>3.4	Functions that materialize the complete yield of a generator</title>
     <para>
      The three functions in this group: <code>gn:to-array</code>, <code>gn:to-sequence</code>, and <code>gn:to-map</code> 
      are provided to help users debug their own generators and functions on generators.
        <table rules="rows" frame="void">
         <caption><para>Functions that materialize the complete yield of a generator to array, to sequence or to map</para></caption>
	        <thead>
	            <tr><th><emphasis role="bold">Function</emphasis></th> <th><emphasis role="bold">Meaning</emphasis></th></tr>
	        </thead>
		      <tbody>
	          <tr>
	            <td><code>gn:to-array</code></td>
	            <td>Returns an array, whose members are the values of the yield of the supplied <code>$generator</code>.</td>
	          </tr>	 
	          <tr>
	            <td><code>gn:to-sequence</code></td>
	            <td>Returns a sequence, whose items are obtained from the values of the yield of the supplied <code>$generator</code>.
	                Any yield value that is an empty sequence is not represented in the result. 
	            </td>
	          </tr>	 
	          <tr>
	            <td><code>gn:to-map</code></td>
	            <td>Returns a map, whose single entries (key-value pairs)  are obtained from the values of the yield of the supplied <code>$generator</code>.</td>
	          </tr>	 	          
	        </tbody> 
	      </table>    
     </para>
    </section>
  </section>
  <section xml:id="dngen4">
    <title>4. Examples</title>
    <para>
      In the examples we use a few predefined generators and functions. The generators <code>$genFibo</code>  and <code>$genLeafAndAncestorNames</code> 
      have already been defined in this paper. We also will use this generator:
<programlisting language="xpath" xml:space="preserve">
let $gen2ToInf := f:generator(initialized := true(), 
                              end-reached := false(), 
                              get-current := fn($this as f:generator) 
                                               {$this?state?last +1}, 
                              move-next :=   fn($this as f:generator)
                              {
                                map:put($this, "state", 
                                               map{"last": $this?state?last + 1})
                              },
                              state := map{"last" : 1}
                             )
      
</programlisting>      
    </para>
    <para>
      <emphasis role="ital">get-current</emphasis>  produces  <code>$this?state?last +1</code>. Because <code>$this?state?last</code> is initially defined as <code>1</code>, 
      the first value of the yield, before <emphasis role="ital">move-next</emphasis>  is called, is <code>2</code>. 
      Each call to <emphasis role="ital">move-next</emphasis> produces a new generator instance in which the value of <code>$this?state?last</code> 
      is the incremented value of <code>$this?state?last</code>  from the previous instance.
    </para>
    <para>
      Thus the values of the yield of <code>$gen2ToInf</code> are all natural numbers, excluding the number one:  
<code>2, 3, 4, 5, 6, 7, …, …</code>
    </para>
    <para>
      It is important to point out here how the user can determine if the yield is finite or infinite. 
      As <code>end-reached</code> is <code>false()</code> and there is nothing in the methods’ code that sets 
      <code>end-reached</code> to <code>true()</code>, the user can deduce that this yield is indeed infinite.
    </para>
    <para>
      This generator (<code>$gen0ToInf</code>) is very similar to <code>$gen2ToInf</code> but its yield starts from <code>0</code> and contains all non-negative integers:
<programlisting language="xpath" xml:space="preserve">
let $gen0ToInf := f:generator(initialized := true(), 
                              end-reached := false(), 
                              get-current := fn($this as f:generator) 
                                               {$this?state?last +1}, 
                              move-next :=   fn($this as f:generator)
                              {
                                map:put($this, "state", 
                                               map{"last": $this?state?last + 1})
                              },
                              state := map{"last" : -1}
                             )      
</programlisting>        
    </para>
    <para>
      And one more similar generator, this time defined as a modification of  <code>$gen2ToInf</code> :
<programlisting language="xpath" xml:space="preserve">
let $genN := $gen2ToInf =&gt; map:put("state", map{"last": 0})             
</programlisting>
    </para>
    <para>
      We will also use a few functions.
    </para>
    <para>
      <code>$double</code> returns twice its argument:
<programlisting language="xpath" xml:space="preserve">
$double := fn($n) {2*$n}
</programlisting>     
    </para>
    <para>
      <code>$sum2</code> returns the sum of its two arguments:
<programlisting language="xpath" xml:space="preserve">
$sum2 := fn($m, $n) {$m + $n}
</programlisting>           
    </para>
    <para>
      <code>$product</code> returns the product of the two numbers <code>$x</code> and <code>$y</code>:
<programlisting language="xpath" xml:space="preserve">
$product := fn($x, $y) {$x * $y}
</programlisting>           
    </para>
    <para>
      <code>$factorial</code> returns the factorial of the number <code>$n</code> :
<programlisting language="xpath" xml:space="preserve">
$factorial := fn($n) {fold-left(1 to $n, 1, $product)}
</programlisting>           
    </para>
    
    <section xml:id="dngen4-1">
      <title>4.1	Using <code>gn:to-array</code>, <code>gn:take</code>, <code>gn:value</code> and <code>gn:next</code></title>
      <para>
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:take(3) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[2,3,4]</code></para>
      <para>
        The first step in the chain:  <code>$gen2ToInf =&gt; gn:take(3)</code> produces a new generator, 
        whose yield consists of the first three values of the yield of  <code>$gen2ToInf</code>. 
      </para>
      <para>
        The final step in the chain   <code>=&gt; gn:to-array()</code>  takes this intermediate result (generator) 
        and materializes its complete yield as the XPath array <code>[2,3,4]</code>.
      </para>
      <para>
        Let us now materialize the yield of the generator already defined as <code>$genLeafAndAncestorNames</code>:
<programlisting language="xpath" xml:space="preserve">
$genLeafAndAncestorNames =&gt; gn:to-array()
</programlisting>
      Produces the array: <code>["z","y","x","/"]</code></para>
      <para>
        The functions <code>gn:value</code> and <code>gn:next</code> are synonyms for the methods <emphasis role="ital">get-current</emphasis> 
        and <emphasis role="ital">move-next</emphasis> 
        but have lower precedence than method calls and can be chained with the <code>=&gt;</code> operator without requiring parenthesis.
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:take(3) =&gt; gn:value()
</programlisting>
        is equivalent to (note the additional parenthesis):
<programlisting language="xpath" xml:space="preserve">
($gen2ToInf =&gt; gn:take(3) ) =?&gt; get-current()
</programlisting>
        and
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:take(3) =&gt; gn:next()
</programlisting>
        is equivalent to (note the additional parenthesis):
<programlisting language="xpath" xml:space="preserve">
( $gen2ToInf =&gt; gn:take(3) ) =?&gt; move-next()
</programlisting>      
      </para>
    </section>
    <section xml:id="dngen4-2">
      <title>4.2	Using <code>gn:fold-left</code>, <code>gn:fold-right</code>, <code>gn:scan-left</code> and <code>gn:scan-right</code></title>
      <para>
        The expression: 
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:take(5) =&gt; gn:fold-left(0, fn($x, $y){$x + $y})
</programlisting>
        Produces: <code>20</code></para>
      <para>
        The expression: 
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:take(5) =&gt; gn:fold-right(0, fn($x, $y){$x + $y})
</programlisting>
        Produces: <code>20</code></para>
      <para>
        The expression: 
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:take(5) =&gt; gn:scan-left(0, fn($x, $y){$x + $y}) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[0, 2, 5, 9, 14, 20]</code></para>
      <para>
        The expression: 
<programlisting language="xpath" xml:space="preserve">
$genN =&gt; gn:take(10) =&gt; gn:scan-right(0, fn($x, $y){$x + $y}) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[55, 54, 52, 49, 45, 40, 34, 27, 19, 10, 0]</code></para>
    </section>
    <section xml:id="dngen4-3">
      <title>4.3	Using <code>gn:subrange</code>, <code>gn:at</code>, <code>gn:head</code> and <code>gn:tail</code></title>
      <para>
        The expression: 
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:subrange(4, 6) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[5, 6, 7]</code>
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:at(5)
</programlisting>
        Produces: <code>6</code>
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:subrange(4, 6) =&gt; gn:head()
</programlisting>
        Produces: <code>5</code>
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:subrange(4, 6) =&gt; gn:tail() =&gt; gn:to-array()
</programlisting>
        Produces: <code>[6, 7]</code>
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:tail()=&gt; gn:head()
</programlisting>
        Produces: <code>3</code></para>
    </section>   
    <section xml:id="dngen4-4">
      <title>4.4	Using <code>gn:for-each</code>, <code>gn:for-each-pair</code>, and <code>gn:filter</code></title>
      <para>
        This expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:for-each($double) =&gt; gn:take(5) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[4, 6, 8, 10, 12]</code></para>
      <para>
        This expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:filter(fn($n){$n mod 2 eq 1}) =&gt; gn:take(10) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[3, 5, 7, 9, 11, 13, 15, 17, 19, 21]</code></para>        
   
      <para>
        This expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:for-each-pair($gen2ToInf, $sum2) =&gt; gn:take(5) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[4, 6, 8, 10, 12]</code></para>
      <para>
        This expression:
<programlisting language="xpath" xml:space="preserve">
$gen0toInf =&gt; gn:for-each(fn($n){(2*$n + 1) div $factorial(2*xs:decimal($n))}) 
           =&gt; gn:take(8) =&gt; gn:fold-left(0, fn($x, $y){$x + $y})
</programlisting>
        Produces: <code>2.718281828458229747</code>  (: Euler’s number <emphasis role="bital">e</emphasis> [<xref linkend="e-wiki"/>] 
        with 11 correct decimal digits :)</para>     
      <para>
        This expression:
<programlisting language="xpath" xml:space="preserve">
$gen0toInf =&gt; gn:for-each(fn($n){(2*$n + 1) div $factorial(2*xs:decimal($n))}) =&gt;   
              gn:take(8) =&gt; gn:scan-left(0, fn($x, $y){$x + $y}) =&gt; gn:to-array()
</programlisting>
        Produces an array of all intermediate fold results in reaching the result of the previous example:
        <code>[0, 1, 2.5, 2.708333333333333333, 2.718055555555555555, 2.718278769841269841, 2.718281801146384479, 2.718281828286168563,2.718281828458229747]</code></para>        
    </section>
    <section xml:id="dngen4-5">
      <title>4.5	Using <code>gn:skip</code>, <code>gn:skip-while</code>, and <code>gn:take-while</code></title>
      <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:take(10) =&gt; gn:skip(3) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[5, 6, 7, 8, 9, 10, 11]</code></para>        
       <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:skip(3) =&gt; gn:take(10) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[5, 6, 7, 8, 9, 10, 11, 12, 13, 14]</code></para>        
       <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:skip-while(fn($n){$n lt 11}) =&gt; gn:take(5) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[11, 12, 13, 14, 15]</code></para>        
       <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:take-while(fn($n){$n lt 11}) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[2, 3, 4, 5, 6, 7, 8, 9, 10]</code></para>        
      <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:take-while(fn($n){$n lt 100000000}) =&gt; gn:value()
</programlisting>
        Produces (instantly): <code>2</code></para>      
    </section>
    <section xml:id="dngen4-6">
      <title>4.6	Using <code>gn:chunk</code></title>
      <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:chunk(10) =&gt; gn:value()
</programlisting>
        Produces: <code>[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]</code></para>        
       <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:take(10) =&gt; gn:chunk(4) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[[2,3,4,5],[6,7,8,9],[10,11]]</code></para>        
       <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:take(10) =&gt; gn:chunk(4) =&gt; gn:for-each(fn($arr) {array-size($arr)})     
           =&gt; gn:to-array()
</programlisting>
        Produces: <code>[4, 4, 2]</code></para>        
    </section>
    <section xml:id="dngen4-7">
      <title>4.7 Using <code>gn:concat</code>, <code>gn:append</code>, <code>gn:prepend</code>, <code>gn:replace</code>, <code>gn:insert-at</code>, <code>gn:remove-at</code></title>
      <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:subrange(10, 15) =&gt; gn:concat($gen2ToInf =&gt; gn:subrange(1, 9)) 
           =&gt; gn:to-array()
</programlisting>
        Produces: <code>[11, 12, 13, 14, 15, 16, 2, 3, 4, 5, 6, 7, 8, 9, 10]</code></para>        
      <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:subrange(1, 5) =&gt; gn:append(101) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[2, 3, 4, 5, 6, 101]</code></para>        
       <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:subrange(1, 5) =&gt; gn:prepend(101) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[101, 2, 3, 4, 5, 6]</code></para>        
       <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:replace(fn($x){$x gt 4}, "Replacement") =&gt; gn:take(10) 
           =&gt; gn:to-array()
</programlisting>
        Produces: <code>[2, 3, 4, "Replacement", 6, 7, 8, 9, 10, 11]</code></para>        
      <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:insert-at(3, "XYZ") =&gt; gn:take(10) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[2, 3, "XYZ", 4, 5, 6, 7, 8, 9, 10]</code></para>        
      <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:remove-at(3) =&gt; gn:take(10) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[2, 3, 5, 6, 7, 8, 9, 10, 11, 12]</code>   (: The number 4 has been removed :)</para>        
    </section>
    <section xml:id="dngen4-8">
      <title>4.8	Using <code>gn:empty-generator</code>, <code>gn:contains</code>, <code>gn:some</code>, <code>gn:some-where</code>, <code>gn:first-where</code>, <code>gn:remove-where</code></title>
        <para>
         The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:take(10) =&gt; gn:contains(3)
</programlisting>
         Produces: <code>true()</code></para>      
        <para>
         The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:take(10) =&gt; gn:contains(20)
</programlisting>
         Produces: <code>false()</code></para>      
        <para>
         The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:contains(100)
</programlisting>
         Produces: <code>true()</code></para>      
        <para>
         The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:some()
</programlisting>
         Produces:<code>true()</code></para>      
        <para>
         The expression:
<programlisting language="xpath" xml:space="preserve">
gn:empty-generator =&gt; gn:some()
</programlisting>
         Produces:<code>false()</code></para>      
        <para>
         The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:take(5) =&gt; gn:filter(fn($n){$n ge 7}) =&gt; gn:some()
</programlisting>
         Produces:<code>false()</code></para>      
        <para>
         The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:take(5) =&gt; gn:some-where(fn($n){$n ge 7})
</programlisting>
         Produces:<code>false()</code></para>      
        <para>
         The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:take(5) =&gt; gn:some-where(fn($n){$n ge 6})
</programlisting>
         Produces:<code>true()</code></para>      
        <para>
         The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:first-where(fn($n){$n gt 10})
</programlisting>
         Produces: <code>11</code></para>      
      <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:chunk(10) 
           =&gt;  gn:first-where(fn($arr as array(*)){$arr(1) le 33 and $arr(10) ge 33})
</programlisting>
        Produces: <code>[32,33,34,35,36,37,38,39,40,41]</code></para>        
      <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:remove-where(fn($x){$x mod 3 eq 0}) =&gt; gn:take(10) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[2, 4, 5, 7, 8, 10, 11, 13, 14, 16]</code></para>    
    </section>
    <section xml:id="dngen4-9">
      <title>4.9	Using <code>gn:distinct</code>, <code>gn:zip</code></title>
      <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
$gen2ToInf =&gt; gn:for-each(fn($n){$n idiv 10}) =&gt; gn:distinct() =&gt; gn:take(15) 
           =&gt; gn:to-array()
</programlisting>
        Produces: <code>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]</code></para>
        <para>
The expression:
<programlisting language="xpath" xml:space="preserve">
let $genSeqE := ($gen0toInf 
                  =&gt; gn:for-each(fn($n)
                                 {(2*$n + 1) div $factorial(2*xs:decimal($n))}
                 ) 
                 =&gt; gn:take(8)) =&gt; gn:scan-left(0, fn($x, $y){$x + $y}),
    $genSeqE-Next := $genSeqE =&gt; gn:tail(),
    $genZipped := $genSeqE =&gt; gn:zip($genSeqE-Next)
 return
  ($genZipped =&gt; gn:first-where(fn($pair){abs($pair(1) - $pair(2)) lt 0.000001}))(2)
</programlisting>
        Produces: <code>2.718281828286168563</code>    (: The first value in the sequence calculating <emphasis role="bital">e</emphasis>, 
        which is less than <emphasis role="ital">0.000001</emphasis> different from the previous value :)    
      </para>             
    </section>
    <section xml:id="dngen4-10">
      <title>4.10	Using <code>gn:make-generator</code>, <code>gn:make-generator-from-array</code>, <code>gn:make-generator-from-sequence</code></title>
      <para>
        The expression:
<programlisting language="xpath" xml:space="preserve">
gn:make-generator(fn($state as array(*))
                  {                                                  
                   let $numGenerated := if(array:empty($state)) then 0
                                          else $state(1)
                     return
                       if($numGenerated le 9) 
                         then [ [$numGenerated + 1], [$numGenerated + 1] ]
                         else [[-1], []]
                   } 
                   ) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]</code></para>       
      <para>Let us try to understand the above example.</para>  
      <para>
        The call to <code>gn:make-generator</code> above passes to it a “provider function” that accepts as its only argument 
        a <code>$state</code> array. This <code>$state</code> array contains a single member, 
        which is the last state reached by the provider and allows the provider to continue forward from this state.
      </para>  
      <para>
        In calling a provider-function, there are three rules/conventions to comply with:
        <orderedlist>
          <listitem>
            <para>It is a convention that on the initial/first call to the provider, the caller should pass an empty <code>$state</code> array.</para>
          </listitem>
          <listitem>
            <para>The provider must return an array with two members, each of them arrays. The first member of the result is an array 
                  containing as its only member the last state reached by the provider. 
                  The second member of the returned result-array is an array that contains the latest value from the data source -  
                  the value (returned by <emphasis role="ital">get-current</emphasis>) of the generator instance.
            </para>
          </listitem>
          <listitem>
            <para>Another rule is that when the data source is exhausted and there are no more values to be returned, 
                  the provider returns an empty array as the second member of the result-array. 
                  In this case the contents of the first member of the result-array is unimportant as it will be ignored.
            </para>
          </listitem>
        </orderedlist>
      </para>   
      <para>In the example above the provider must return on each call the numbers from <code>1</code> to <code>10</code>.
The contents of the <code>$state</code> array is the last number that was returned. 
If the last number returned was greater than <code>9</code> (this is the exceptional case), then the provider signals 
that the data-source has been exhausted – by returning a result array of <code>[[-1], []]</code> 
where the second member that should contain the next returned value actually contains nothing.

      </para> 
      <para>
        In the “normal case” when the last number returned is not bigger than <code>9</code>, 
        the provider returns the incremented value of this last number <code>[ [$numGenerated + 1], [$numGenerated + 1] ]</code>  - 
        both as its next state and as the next value to be used by the generator. 
      </para>  
      <para>
        In the next example, the provider-function produces all natural numbers: <code>1, 2, 3, … </code>and never sets the second member 
        of its result-array to an empty array. <emphasis role="bold">The resulting generator instance has an infinite yield</emphasis>, 
        but we may still obtain its current value, or a subrange of the values of its yield:
<programlisting language="xpath" xml:space="preserve">
let $allNumbers :=  gn:make-generator(fn($state as array(*))
                    {
                      let $numGenerated := if(array:empty($state)) 
                                              then 0
                                              else $state(1)
                        return
                           [ [$numGenerated + 1], [$numGenerated + 1] ]
                      }) 
      return ($allNumbers =&gt; gn:value(), 
              $allNumbers =&gt; gn:subrange(10, 15) =&gt; gn:to-array())
</programlisting>
         Produces: <code>1, [10, 11, 12, 13, 14, 15]</code></para>
      <para>
        This expression:
<programlisting language="xpath" xml:space="preserve">
gn:make-generator-from-array([1, 4, 9, 16, 25]) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[1, 4, 9, 16, 25]</code></para>    
      <para>
        This expression:
<programlisting language="xpath" xml:space="preserve">
gn:make-generator-from-array([]) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[]</code></para>    
      <para>
        This expression:
<programlisting language="xpath" xml:space="preserve">
gn:make-generator-from-sequence((1, 8, 27, 64, 125)) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[1, 8, 27, 64, 125]</code></para>    
    </section>
    <section xml:id="dngen4-11">
      <title>4.11	N-way merge of generators with sorted yields: <code>gn:merge-sorted-generators</code></title>
      <para>
        The N-way merge of data sources is essential in implementing external sort. The following examples show its use, 
        including in the last example the merge of three generators with infinite yields.
      </para>
      <para>
        This expression:
<programlisting language="xpath" xml:space="preserve">
     let $ar1 := [-100, -4, 1, 3, 5, 7, 9, 11],
         $ar2 :=  [-100, -90, -80, -70, -60, -50],
         $ar3 := [-10, -8, -6, -4, -2, 0, 15],
         $gn1 := gn:make-generator-from-array($ar1),
         $gn2 := gn:make-generator-from-array($ar2),
         $gn3 := gn:make-generator-from-array($ar3),
         $genOfGens := gn:make-generator-from-array([$gn1, $gn2, $gn3])
       return
         gn:merge-sorted-generators($genOfGens) =&gt; gn:to-array()
</programlisting>
        Produces: <code>[-100,-100,-90,-80,-70,-60,-50,-10,-8,-6,-4,-4,-2,0,1,3,5,7,9,11,15]</code></para>       
      <para>
        This expression:
<programlisting language="xpath" xml:space="preserve">
     let $ar1 := array {1 to 100_000_000_000},
         $ar2 := array {2 to 100_000_000_001},
         $ar3 := array {3 to 100_000_000_002},
         $gn1 := gn:make-generator-from-array($ar1),
         $gn2 := gn:make-generator-from-array($ar2),
         $gn3 := gn:make-generator-from-array($ar3),
         $genOfGens := gn:make-generator-from-array([$gn1, $gn2, $gn3])
     return
       gn:merge-sorted-generators($genOfGens) =&gt; gn:subrange(1, 30) 
                 =&gt; gn:to-array()
</programlisting>
        Produces: <code>[1,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,8,8,8,9,9,9,10,10,10,11,11,11]</code></para>       
      <para>
        This expression:
<programlisting language="xpath" xml:space="preserve">
     let $gn1 := gn:make-generator(fn($state as array(*))
                                 {
                                  let $numGenerated := if(array:empty($state)) 
                                       then 0
                                       else $state[1]
                                    return
                                      [ [$numGenerated + 2], [$numGenerated + 2] ]
                                  }
                                   ),
         $gn2 := gn:make-generator(fn($state as array(*))
                                 {
                                  let $numGenerated := if(array:empty($state)) 
                                      then 0
                                      else $state[1]
                                    return
                                      [ [$numGenerated + 3], [$numGenerated + 3] ]
                                  }
                                   ),
         $gn3 := gn:make-generator(fn($state as array(*))
                                 {
                                  let $numGenerated := if(array:empty($state)) 
                                      then 0
                                      else $state[1]
                                    return
                                      [ [$numGenerated + 5], [$numGenerated + 5] ]
                                 }
                                   ),
         $genOfGens := gn:make-generator-from-array([$gn1, $gn2, $gn3])
     return
       gn:merge-sorted-generators($genOfGens) =&gt; gn:subrange(1, 40) 
                 =&gt; gn:to-array()
</programlisting>
        Produces: <code>[2,3,4,5,6,6,8,9,10,10,12,12,14,15,15,16,18,18,20,20,21,22,24,24,25,26,27,28,30,30,30,32,33,34,35,36,36,38,39,40]</code></para>       
    </section>
  </section>
  <section xml:id="dngen5">
   <title>5.	The Deferred-Evaluation Programming style</title>
   <para>
     The introduction of generators into XPath enables a fundamentally different programming style, referred to here 
     as <emphasis role="bold">deferred evaluation</emphasis> [<xref linkend="defeval-microsoft"/>] [<xref linkend="lazy-wiki"/>]. 
     This style departs from the traditional, 
     sequence-oriented evaluation model of XPath, where expressions are typically evaluated eagerly 
     and results are materialized as complete sequences.
   </para>
   <para>
     At the core of deferred evaluation is the observation that, at any given point in the evaluation, 
     a generator instance represents <emphasis role="bold">at most one value</emphasis> from its yield. 
     The remainder of the yield is not computed in advance, nor is it required to exist in memory. 
     Instead, the computation of subsequent values is <emphasis role="ital">deferred</emphasis> until explicitly requested.
   </para>
   <section xml:id="dngen5-1">
     <title>5.1	Demand-Driven Computation</title>
     <para>
       With deferred-evaluation, values are produced <emphasis role="bold">only on demand</emphasis>.
     </para>
     <para>
       A generator does not compute its entire yield. Rather, it defines how to compute the next value, should such a request occur. 
       The method  <emphasis role="ital">move-next</emphasis>  realizes this potential for future computation. 
       Importantly, this method is not invoked automatically; it is invoked only when the consumer of the generator explicitly requests the next value.
     </para>
     <para>
       As a consequence, it is entirely possible—and often desirable—that only a finite prefix of a potentially infinite yield is ever computed. 
       In many cases, only the first value is required, and no further computation takes place.
     </para>
   </section>
   <section xml:id="dngen5-2">
     <title>5.2	Separation of Description from Execution</title>
     <para>
      A key characteristic of this programming style is the separation between:
      <itemizedlist>
        <listitem>
          <para><emphasis role="bold">describing a computation</emphasis>, and</para>
        </listitem>
        <listitem>
          <para><emphasis role="bold">executing a computation</emphasis></para>
        </listitem>
      </itemizedlist>
     </para>
     <para>
       When composing generator-based expressions, the programmer specifies 
       <emphasis role="ital">what should happen if further values are requested</emphasis>, but does not cause those requests to occur.
     </para>
     <para>
       In this sense, a generator-based expression does not directly compute a result. 
       Instead, it constructs a <emphasis role="bold">computational process</emphasis> — a description of how yield-values may be produced in the future. 
       The actual execution of this process is controlled externally, by the consumer of the generator.
     </para>
     <para>
       This leads to an important conceptual shift:
     </para>
     <para>
       A generator-based program is not merely a program that computes values, but a program that constructs another program—namely, a deferred computation.
     </para>
   </section>
   <section xml:id="dngen5-3">
     <title>5.3	Controlled Evaluation and Early Termination</title>
     <para>
       Because evaluation is demand-driven, the consumer of a generator has full control over how much of the yield is explored.
     </para>
     <para>
       Functions that produce only a single yield-value (such as <code>gn:head</code>, <code>gn:first-where</code>, or <code>gn:at</code>) 
       evaluate only as much of the yield as is necessary to produce that value. Once the result is obtained, no further yield-values are generated.
     </para>
     <para>
       This enables <emphasis role="bold">early termination</emphasis> of computations in a natural and composable way, 
       without requiring special control constructs. In particular, it allows safe and practical interaction with generators whose yields are:
       <itemizedlist>
         <listitem>
           <para>very large, or </para>
         </listitem>
         <listitem>
           <para>infinite</para>
         </listitem>
       </itemizedlist>
     </para>
   </section>
    <section xml:id="dngen5-4">
      <title>5.4	Deferred Evaluation vs Recursion</title>  
      <para>Deferred evaluation should not be confused with recursion [<xref linkend="recursion-wiki"/>] .</para>
      <para>
        In XPath, recursive functions are typically evaluated eagerly: each recursive call contributes to the construction 
        of a fully materialized result. Even when tail-call optimization is available, the evaluation strategy remains fundamentally eager.
      </para>
      <para>
        In contrast, generator-based computation does not build a complete resulting yield. 
        Instead, it defines a <emphasis role="ital">stepwise process</emphasis> in which each step produces at most one yield-value 
        and a description of the next step.
      </para>
      <para>
        Thus, while evaluation of recursion <emphasis role="ital">traverses a structure</emphasis>, 
        evaluation of a generator’s <emphasis role="ital">move-next</emphasis> method creates a  
        <emphasis role="ital">description  how to produce a structure incrementally</emphasis>.
      </para>
    </section>
    <section xml:id="dngen5-5">
      <title>5.5	Minimal State and Memory Efficiency</title>
      <para>
        At any point during evaluation, only the current generator instance and its associated state is required. 
        No storage is needed for previously produced values unless explicitly retained by the user.
      </para>
      <para>
        This results in:
        <itemizedlist>
          <listitem>
            <para><emphasis role="bold">constant memory usage</emphasis> for many classes of problems</para>
          </listitem>
          <listitem>
            <para>the ability to process <emphasis role="bold">unbounded or infinite data sources</emphasis></para>
          </listitem>
          <listitem>
            <para>elimination of unnecessary intermediate materialization</para>
          </listitem>
        </itemizedlist>
      </para>
    </section>
    <section xml:id="dngen5-6">
      <title>5.6	Composability of Deferred Computations</title>
      <para>
        Generator-transforming functions (such as <code>gn:filter</code>, <code>gn:for-each</code>, and <code>gn:take</code>) 
        defined in <xref linkend="dngen3-2"/> do not simply evaluate 
        their input generators. Instead, they construct new generators that incorporate additional behavior into the deferred computation.
      </para>
      <para>
        This allows arbitrarily long chains of transformations to be defined without triggering evaluation. 
        The entire chain remains dormant until a yield-value is explicitly requested.
      </para>
      <para>
        As a result, complex data-processing pipelines can be expressed declaratively while retaining precise control over evaluation. 
      </para>
    </section>
    <section xml:id="dngen5-7">
       <title>5.7	Summary</title>
       <para>
         Deferred evaluation in XPath, as enabled by generators, introduces a programming model characterized by:
         <itemizedlist>
           <listitem><para>separation of computation description from execution</para></listitem>
           <listitem><para>demand-driven computation</para></listitem>
           <listitem><para>explicit control over evaluation</para></listitem>
           <listitem><para>efficient handling of large or infinite data</para></listitem>
           <listitem><para>high composability of transformations</para></listitem>
         </itemizedlist>
       </para> 
       <para>
         This model complements the existing sequence-based approach in XPath, extending the language with a powerful abstraction 
         for incremental and resource-efficient computation.
       </para>
       <para>
         The table below is a comparison between typical eager XPath evaluation and generator-based, deferred evaluation:
        <table rules="rows" frame="void">
         <caption><para>Comparison between typical eager XPath evaluation and generator-based, deferred evaluation</para></caption>
	        <thead>
	            <tr><th><emphasis role="bold">Feature</emphasis></th> 
                  <th><emphasis role="bold">Eager XPath</emphasis></th>
                  <th><emphasis role="bold">Deferred</emphasis></th>
              </tr>
	        </thead>
		      <tbody>
		        <tr><td>Evaluation</td>
                <td>Immediate</td>
                <td>Deferred</td>
            </tr>
		        <tr><td>Memory</td>
                <td>Full sequence</td>
                <td>Incremental</td>
            </tr>
		        <tr><td>Infinite/Unbounded data</td>
                 <td>Impossible</td>
                 <td>Natural</td>
            </tr>
		        <tr><td>Control</td>
                <td>Implicit</td>
                <td>Explicit</td>
           </tr>
		      </tbody>
        </table> 
       </para>
    </section>
  </section>
  <section xml:id="dngen6">
    <title>6.	A Real World Use-Case</title>
    <para>
      The generator abstraction introduced in this paper is not merely a theoretical construct, but a practical tool for addressing 
      real-world data-processing problems that involve large, unbounded, or externally provided data sources. 
      This section presents a representative use case [<xref linkend="gen-usecase"/>] : the aggregation of multiple news feeds. 
      This scenario highlights the advantages of deferred evaluation, composability, and integration with external data providers.
    </para>
    <section xml:id="dngen6-1">
      <title>6.1 The Problem: Aggregation of Multiple News Feeds</title>
      <para>
        Consider the problem of aggregating multiple news feeds, such as RSS [<xref linkend="rss-spec"/>] 
        or Atom [<xref linkend="atom-spec"/>]  sources, 
        into a single, unified stream of entries. 
        Each feed may contain a large number of items and may be updated independently over time. 
        A typical requirement is to present the most recent entries across all feeds, possibly filtered by relevance, 
        and limited to a fixed number of results (e.g., the most recent 20 items).
      </para>
      <para>
        This problem raises several challenges:
        <itemizedlist>
         <listitem><para>Each feed may be large or conceptually unbounded.</para></listitem>
         <listitem><para>Accessing a feed may require communication with an external system (e.g., over HTTP).</para></listitem>
         <listitem><para>The combined result must be ordered (e.g., by publication date-time).</para></listitem>
         <listitem><para>Only a small prefix of the combined result is typically needed.</para></listitem>
         <listitem><para>Early termination is essential to avoid unnecessary data retrieval and processing.</para></listitem>
        </itemizedlist>
      </para>
      <para>
        In a purely sequence-based approach in XPath, all input feeds would need to be fully materialized before merging, 
        sorting, and filtering could be performed. This approach is inefficient and, in some cases, infeasible.
      </para>
      <para>
        One can have a glimpse at the “Top 100 World News RSS Feeds” [<xref linkend="top-feeds"/>]. Each news-feed may contain 20 or more news-items, 
        and each news-item may point to an external html document, or may contain the content inline. 
        Even if we only process the top 15 news feeds, we may have to deal with more than 300 news-items and related documents. 
        And the Mar. 26th Dow Jones RSS newsfeed [<xref linkend="dowj-rss"/>] alone contained not 20 but 75 &lt;item&gt; elements.
      </para>
    </section>
    <section xml:id="dngen6-2">
      <title>6.2 Generator-Based Solution</title>
      <para>
        Using generators, each news feed can be represented as a generator whose yield consists of the items in that feed, 
        obtained incrementally via an external provider
      </para>
      <para>
       A typical processing pipeline can be expressed as follows:
<programlisting xml:space="preserve">
$feedLocations
=&gt; gn:for-each($fetch-feed) 
=&gt; gn:merge-sorted-generators()
=&gt; gn:filter($is-relevant)
=&gt; gn:take(20)
=&gt; gn:to-array()
</programlisting>
       In this pipeline:
       <itemizedlist>
          <listitem>
             <para>
                <code>$feedLocations</code> is a generator whose yield is a collection of feed descriptors (e.g., URLs).
             </para>
          </listitem>
          <listitem>
             <para>
                <code>$fetch-feed</code> is a function that, given a feed descriptor, returns a generator backed 
                by an external provider that retrieves feed items incrementally. 
             </para>
          </listitem>
          <listitem>
             <para>
                <code>gn:merge-sorted-generators</code>  merges multiple generators whose yields are already sorted (e.g., by publication date), 
                producing a single sorted generator. 
             </para>
          </listitem>
          <listitem>
             <para>
                <code>gn:filter</code>  removes items that are not relevant according to a specified predicate. 
             </para>
          </listitem>
          <listitem>
             <para>
                <code>gn:take(20)</code> limits the result to the first 20 items. 
             </para>
          </listitem>
          <listitem>
             <para>
                <code>gn:to-array()</code> materializes the result for presentation. 
             </para>
          </listitem>
       </itemizedlist>
       The expression, preceding  “<code>=&gt; gn:to-array()</code>” defines a complete data-processing pipeline 
       without forcing the evaluation of any intermediate results. The evaluation and production of results starts only 
       within the call to <code>gn:to-array()</code>.
      </para>
    </section>    
    <section xml:id="dngen6-3">
      <title>6.3 Incremental Evaluation and Early Termination</title>
      <para>A key advantage of this approach is that evaluation proceeds incrementally and only as far as necessary.</para>
      <para>
        In the example above, once 20 items are produced as specified by <code>gn:take(20)</code>, 
        no further values are requested from the upstream generators. As a result:
        <itemizedlist>
          <listitem><para>Each feed is accessed only as much as required to contribute to the first 20 results.</para></listitem>
          <listitem><para>No unnecessary network requests are made.</para></listitem>
          <listitem><para>No excess data is retained in memory.</para></listitem>
        </itemizedlist>
        This behavior is particularly important when dealing with large or continuously updated feeds, 
        where the total number of available items may be very large or effectively unbounded.
      </para>
    </section>
    <section xml:id="dngen6-4">
      <title>6.4 External Data Providers</title>
      <para>The integration of generators with external data providers is essential in this scenario.</para>
      <para>
        Each feed generator is constructed using a provider function that encapsulates:
        <itemizedlist>
          <listitem><para>the state required to continue fetching items (e.g., pagination tokens and items transmitted within the current page), and</para></listitem>
          <listitem><para>the logic for retrieving the next item from the feed</para></listitem>
        </itemizedlist>
        The provider communicates with the generator through the contract defined in Section 3.3, 
        returning both updated state and the next available item (if any). This allows the generator to present a uniform interface 
        regardless of the underlying data source.
      </para>
      <para>
        By abstracting external access in this way, generators enable XPath expressions to interact seamlessly with:
        <itemizedlist>
          <listitem><para>remote feeds (HTTP-based APIs),</para></listitem>
          <listitem><para>databases (streaming query result sets or via cursor-like mechanisms),</para></listitem>
          <listitem><para>file streams, and</para></listitem>
          <listitem><para>other incremental data sources.</para></listitem>         
        </itemizedlist>
      </para>
    </section>
    <section xml:id="dngen6-5">
      <title>6.5 Comparison with Eager Evaluation</title>
      <para>
        To better understand the benefits of the generator-based approach, it is useful to contrast it with a traditional eager evaluation strategy.
      </para>
      <para>
        In an eager approach, the processing would conceptually involve:
        <orderedlist>
          <listitem><para>Fetching all items from all feeds</para></listitem>
          <listitem><para>Producing a single, combined sequence of all results</para></listitem>
          <listitem><para>Sorting the combined sequence</para></listitem>
          <listitem><para>Filtering irrelevant items</para></listitem>
          <listitem><para>Selecting the first 20 entries</para></listitem>
        </orderedlist>
        This approach requires full materialization of all intermediate results and does not support early termination.
      </para>
      <para>
        In contrast, the generator-based approach:
        <itemizedlist>
          <listitem><para>fetches items lazily,</para></listitem>
          <listitem><para>merges them incrementally,</para></listitem>
          <listitem><para>applies filtering on demand, and</para></listitem>
          <listitem><para>stops as soon as the required number of results has been obtained.</para></listitem>
        </itemizedlist>
        This results in significantly improved efficiency and scalability.
      </para>
    </section> 
    <section xml:id="dngen6-6">
      <title>6.6 Generalization</title>
      <para>
        Although presented in the context of news feed aggregation, the same pattern applies to a wide range of problems, including:
        <itemizedlist>
          <listitem><para>processing large XML documents in a streaming fashion,</para></listitem>
          <listitem><para>merging sorted data from multiple databases,</para></listitem>
          <listitem><para>consuming paginated web APIs,</para></listitem>
          <listitem><para>analyzing log streams, and</para></listitem>
          <listitem><para>performing computations over infinite or computationally generated sequences.</para></listitem>
        </itemizedlist>
        In all these cases, generators provide a uniform and composable abstraction for deferred, incremental computation.
      </para>
    </section> 
    <section xml:id="dngen6-7">
      <title>6.7 Summary</title>
      <para>
        This use case demonstrates how generators enable:
        <itemizedlist>
          <listitem><para>efficient processing of large and external data sources,</para></listitem>
          <listitem><para>precise control over evaluation and resource usage, and </para></listitem>
          <listitem><para>clear and composable expression of complex data-processing pipelines.</para></listitem>
        </itemizedlist>
        By combining deferred evaluation with a strictly-defined protocol for external data providers, 
        generators extend XPath's power with capabilities that are difficult or near-impossible to achieve 
        using traditional sequence-based techniques alone.
      </para>
    </section>
  </section>
  <section xml:id="dngen7">
    <title>7. Conclusion</title>
    <para>
      This paper introduced a generator-based model for deferred evaluation in XPath 4. 
      Generators address a fundamental omission in the language specification: 
      the agency to efficiently and uniformly process large, unbounded, or externally provided collections of data.
    </para>
    <para>
      The proposed solution is centered on a simple but expressive abstraction that is widely used in other programming languages - the Generator Record. 
      Alongside which we propose a composable set of functions that operate without requiring the full materialization of intermediate results. 
     </para>
     <para>
      This enables a programming style that is fundamentally different from traditional XPath evaluation: 
      one that is demand-driven, incremental, memory-sensitive and externally controllable.
    </para>
    <para>
     Two key contributions distinguish this work:
     <itemizedlist>
       <listitem>
         <para>
           <emphasis role="bold">A composable generator library</emphasis>, allowing complex transformations to be expressed as chains of generator-producing functions, 
           without loss of laziness or control over evaluation.
         </para>
       </listitem>
       <listitem>
         <para>
           <emphasis role="bold">A strictly-defined protocol for external data providers</emphasis>, enabling generators to seamlessly integrate with data sources 
           such as web services, files, and databases, while preserving the declarative nature of XPath.
         </para>
       </listitem>
     </itemizedlist>
     The resulting model allows XPath programs to:
     <itemizedlist>
       <listitem><para>operate over infinite or unbounded data,</para></listitem>
       <listitem><para>terminate early without unnecessary computation,</para></listitem>
       <listitem><para>maintain constant or bounded memory usage, and</para></listitem>
       <listitem><para>express complex data-processing pipelines in a clear and modular way.</para></listitem>
     </itemizedlist>
    </para>
    <para>
      Importantly, this approach is <emphasis role="bold">implementation-independent</emphasis>. It does not rely on vendor-specific optimizations 
      or extensions, but instead provides a portable, formally defined mechanism that is implemented within the XPath language itself.
    </para>
    <para>
      Anyone can grab the existing pure XPath 4 implementation from [<xref linkend="gen-formal"/>], 
      run with BaseX the more than 140 test-cases, and immediately start writing their own generators.
    </para>
    <para>
      The generator abstraction complements, rather than replaces, the existing sequence-based model of XPath. 
      While sequences remain appropriate for finite and fully materialized data, generators extend the usability of XPath 
      into domains traditionally associated with streaming, and functional programming systems.
    </para>
    <para>
      Future work may explore:
      <itemizedlist>
        <listitem><para>formal integration of generators into the XPath and XQuery specifications,</para></listitem>
        <listitem><para>optimization strategies for generator-based pipelines,</para></listitem>
        <listitem><para>static analysis of generator expressions, and</para></listitem>
        <listitem><para>additional abstractions built on top of generators.</para></listitem>
      </itemizedlist>
    </para>
    <para>
      By introducing deferred evaluation as a first-class programming style, this work expands the expressive power of XPath 
      and opens the door to new classes of applications that were previously difficult or impractical to implement.
    </para>
  </section> 
    <section xml:id="dngen-ack">
    <title>Acknowledgements</title>
    <para>
      The author expresses his gratitude to Adam Retter and Alan Painter for their help with the English language 
      and style of this paper, and to Liam Quin for his encouragement.
    </para>
    <para>
      Many thanks to the three anonymous Balisage reviewers for their comments, questions and suggestions.
    </para>
  </section>
  <appendix xml:id="dngen-app1" xreflabel="Appendix I">
    <title>An example of "implementation-dependence magic" in current XPath processors</title>
      <para>
         This is an example of an expression that is evaluated instantly in BaseX, 
         but takes 591 seconds in Saxon, as can be seen in the screenshot below.
<programlisting language="xpath" xml:space="preserve">
let $product := function($m as xs:decimal, $n as xs:decimal)  as xs:decimal {$m * $n} ,
    $factorial := function($n as xs:decimal)  as xs:decimal {fold-left(1 to $n, 1, $product)},
    $f := function($n) {$factorial($n) div $factorial($n -2)}
 return
    (1 to 100000000)[$f(20)]
</programlisting>
      </para>
    <para>
      In order to be able to write really portable XPath code, we need something that would eliminate the risk of 
      surprizes from such implementation-dependence magic.
      
      <mediaobject>
         <imageobject>
           <imagedata format="jpg" fileref="../../../vol31/graphics/Novatchev01/Novatchev01-001.jpg" width="70%"/>
         </imageobject>
      </mediaobject>
    </para>   
  </appendix>
  <bibliography>
      <title>Bibliography</title>
    <bibliomixed xml:id="atom-spec" xreflabel="Atom - Spec">
      <quote><emphasis role="ital">The Atom Syndication Format</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://datatracker.ietf.org/doc/html/rfc4287</link>
    </bibliomixed>
    <bibliomixed xml:id="defeval-microsoft" xreflabel="DefEval - Msft">
      <quote><emphasis role="ital">Deferred execution and lazy evaluation</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://learn.microsoft.com/en-us/dotnet/standard/linq/deferred-execution-lazy-evaluation</link>
    </bibliomixed>
    <bibliomixed xml:id="dowj-rss" xreflabel="DowJones - RSS">
      <quote><emphasis role="ital">Dow Jones RSS newsfeed</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://feeds.content.dowjones.io/public/rss/RSSWorldNews</link>
    </bibliomixed>
    <bibliomixed xml:id="eager-wiki" xreflabel="Eager - Wikipedia">
      <quote><emphasis role="ital">Evaluation-Strategy/Strict-Evaluation</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://en.wikipedia.org/wiki/Evaluation_strategy#Eager_evaluation</link>
    </bibliomixed>
    <bibliomixed xml:id="e-wiki" xreflabel="e - Wikipedia">
      <quote><emphasis role="ital">e (mathematical constant)</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://en.wikipedia.org/wiki/E_(mathematical_constant)</link>
    </bibliomixed>
    <bibliomixed xml:id="fibo-wiki" xreflabel="Fibonacci - Wikipedia">
      <quote><emphasis role="ital">Fibonacci Sequence</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://en.wikipedia.org/wiki/Fibonacci_sequence</link>
    </bibliomixed>
    <bibliomixed xml:id="gen-wiki" xreflabel="Generators - Wikipedia">
      <quote><emphasis role="ital">Generator (computer programming)</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://en.wikipedia.org/wiki/Generator_(computer_programming)</link>
    </bibliomixed>
    <bibliomixed xml:id="gen-formal" xreflabel="Generators - Formal">
      <quote><emphasis role="ital">Generators in XPath - Formal Semantics – Executable XPath/XQuery 4 and 3.1 code</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://github.com/dnovatchev/generators</link>
    </bibliomixed>
    <bibliomixed xml:id="gen-usecase" xreflabel="Generators - Usecase">
      <quote><emphasis role="ital">Use Case for Generators: News Feeds Aggregation using Generators</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://github.com/qt4cg/qtspecs/discussions/2557</link>
    </bibliomixed>
    <bibliomixed xml:id="gen-xpath3" xreflabel="Generators - XPath3">
      <quote><emphasis role="ital">Generators Implementation in XPath 3</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://medium.com/@dimitrenovatchev/generators-in-xpath-987a609cfbd5?sk=6334d48f9565f78eba90b212e461243b</link>
    </bibliomixed>
    <bibliomixed xml:id="lazy-xpath" xreflabel="Laziness - XPath">
      <quote><emphasis role="ital">Laziness in XPath. The trouble with fn:fold-right</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://medium.com/@dimitrenovatchev/laziness-in-xpath-the-trouble-with-fn-fold-right-cbb1cc654d1c?sk=872244cf80bfcb52d67bcb8b359478ff</link>
    </bibliomixed>
    <bibliomixed xml:id="lazy-wiki" xreflabel="Lazy - Wikipedia">
      <quote><emphasis role="ital">Lazy Evaluation</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://en.wikipedia.org/wiki/Lazy_evaluation</link>
    </bibliomixed>
    <bibliomixed xml:id="nway-merge" xreflabel="N-Way-Merge - Wikipedia">
      <quote><emphasis role="ital">K-way merging</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://en.wikipedia.org/wiki/Merge_algorithm#K-way_merging</link>
    </bibliomixed>
    <bibliomixed xml:id="recursion-wiki" xreflabel="Recursion - Wikipedia">
      <quote><emphasis role="ital">Recursion - In Computer Science</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://en.wikipedia.org/wiki/Recursion#In_computer_science</link>
    </bibliomixed>
    <bibliomixed xml:id="rss-spec" xreflabel="RSS - Spec">
      <quote><emphasis role="ital">RSS 2.0 Specification</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://www.rssboard.org/rss-specification</link>
    </bibliomixed>
    <bibliomixed xml:id="saxon-lazy" xreflabel="Saxon - Laziness">
      Michael Kay, <quote><emphasis role="ital">Lazy Evaluation</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://blog.saxonica.com/mike/2015/06/lazy-evaluation.html</link>
    </bibliomixed>
    <bibliomixed xml:id="top-feeds" xreflabel="RSS - TopFeeds">
      <quote><emphasis role="ital">Top 100 World News RSS Feeds</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://rss.feedspot.com/world_news_rss_feeds/</link>
    </bibliomixed>
    <bibliomixed xml:id="xpath-31" xreflabel="XPath 3.1 - Spec">
      <quote><emphasis role="ital">XML Path Language (XPath) 3.1</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://www.w3.org/TR/xpath-31/</link>
    </bibliomixed>
    <bibliomixed xml:id="xpath-4" xreflabel="XPath 4 - Draft">
      <quote><emphasis role="ital">XPath 4.0 WG Review Draft</emphasis></quote>,
      <link xlink:type="simple" xlink:show="new" xlink:actuate="onRequest">https://qt4cg.org/specifications/xquery-40/xpath-40.html</link>
    </bibliomixed>
  </bibliography>
 
</article>