362 lines
13 KiB
HTML
362 lines
13 KiB
HTML
<html>
|
|
<head>
|
|
<title>Lazy Evaluation</title>
|
|
<link rel="stylesheet" type="text/css" href="style.css">
|
|
</head>
|
|
<body>
|
|
<h1>Lazy Evaluation</h1>
|
|
<p>The 'lazy' vocabulary adds lazy lists to Factor. This provides the
|
|
ability to describe infinite structures, and to delay execution of
|
|
expressions until they are actually used.</p>
|
|
<p>Lazy lists, like normal lists, are composed of a head and tail. In
|
|
a lazy list the head and tail are something called a 'promise'.
|
|
To convert a
|
|
'promise' into its actual value a word called 'force' is used. To
|
|
convert a value into a 'promise' the word to use is 'delay'.</p>
|
|
<table border="1">
|
|
<tr><td><a href="#delay">delay</a></td></tr>
|
|
<tr><td><a href="#force">force</a></td></tr>
|
|
</table>
|
|
|
|
<p>Many of the lazy list words are named similar to the standard list
|
|
words but with an 'l' suffixed to it. Here are the commonly used
|
|
words and their equivalent list operation:</p>
|
|
<table border="1">
|
|
<tr><th>Lazy List</th><th>Normal List</th></tr>
|
|
<tr><td><a href="#lnil">lnil</a></td><td>[ ]</td></tr>
|
|
<tr><td><a href="#lnilp">lnil?</a></td><td>Test for nil value</td></tr>
|
|
<tr><td><a href="#lcons">lcons</a></td><td>cons</td></tr>
|
|
<tr><td><a href="#lunit">lunit</a></td><td>unit</td></tr>
|
|
<tr><td><a href="#lcar">lcar</a></td><td>car</td></tr>
|
|
<tr><td><a href="#lcdr">lcdr</a></td><td>cdr</td></tr>
|
|
<tr><td><a href="#lnth">lnth</a></td><td>nth</td></tr>
|
|
<tr><td><a href="#luncons">luncons</a></td><td>uncons</td></tr>
|
|
<tr><td><a href="#lmap">lmap</a></td><td>map</td></tr>
|
|
<tr><td><a href="#lsubset">lsubset</a></td><td>subset</td></tr>
|
|
<tr><td><a href="#leach">leach</a></td><td>each</td></tr>
|
|
<tr><td><a href="#lappend">lappend</a></td><td>append</td></tr>
|
|
</table>
|
|
<p>A few additional words specific to lazy lists are:</p>
|
|
<table border="1">
|
|
<tr><td><a href="#ltake">ltake</a></td><td>Returns a normal list containing a specified
|
|
number of items from the lazy list.</td></tr>
|
|
<tr><td><a href="#lappendstar">lappend*</a></td><td>Given a lazy list of lazy lists,
|
|
concatenate them together in a lazy manner, returning a single lazy
|
|
list.</td></tr>
|
|
<tr><td><a href="#list>llist">list>llist</a></td><td>Given a normal list, return a lazy list
|
|
that contains the same elements as the normal list.</td></tr>
|
|
</table>
|
|
<h2>Reference</h2>
|
|
<!-- delay description -->
|
|
<a name="delay">
|
|
<h3>delay ( quot -- <promise> )</h3>
|
|
<p>'delay' is used to convert a value or expression into a promise.
|
|
The word 'force' is used to convert that promise back to its
|
|
value, or to force evaluation of the expression to return a value.
|
|
</p>
|
|
<p>The value on the stack that 'delay' expects must be quoted. This is
|
|
a requirement to prevent it from being evaluated.
|
|
</p>
|
|
<pre class="code">
|
|
( 1 ) [ 42 ] <a href="#delay">delay</a> dup .
|
|
=> << promise [ ] [ 42 ] [ ] [ ] >>
|
|
( 2 ) <a href="#force">force</a> .
|
|
=> 42
|
|
</pre>
|
|
|
|
<!-- force description -->
|
|
<a name="force">
|
|
<h3>force ( <promise> -- value )</h3>
|
|
<p>'force' will evaluate a promises original expression
|
|
and leave the value of that expression on the stack.
|
|
</p>
|
|
<p>A promise can be forced multiple times but the expression
|
|
is only evaluated once. Future calls of 'force' on the promise
|
|
will returned the cached value of the original force. If the
|
|
expression contains side effects, such as i/o, then that i/o
|
|
will only occur on the first 'force'. See below for an example
|
|
(steps 3-5).
|
|
</p>
|
|
<p>If a promise is itself delayed, a force will evaluate all promises
|
|
until a value is returned. Due to this behaviour it is generally not
|
|
possible to delay a promise. The example below shows what happens
|
|
in this case.
|
|
</p>
|
|
<pre class="code">
|
|
( 1 ) [ 42 ] <a href="#delay">delay</a> dup .
|
|
=> << promise [ ] [ 42 ] [ ] [ ] >>
|
|
( 2 ) <a href="#force">force</a> .
|
|
=> 42
|
|
|
|
#! Multiple forces on a promise returns cached value
|
|
( 3 ) [ "hello" print 42 ] <a href="#delay">delay</a> dup .
|
|
=> << promise [ ] [ "hello" print 42 ] [ ] [ ] >>
|
|
( 4 ) dup <a href="#force">force</a> .
|
|
=> hello
|
|
42
|
|
( 5 ) <a href="#force">force</a> .
|
|
=> 42
|
|
|
|
#! Forcing a delayed promise cascades up to return
|
|
#! original value, rather than the promise.
|
|
( 6 ) [ [ 42 ] <a href="#delay">delay</a> ] <a href="#delay">delay</a> dup .
|
|
=> << promise [ ] [ [ 42 ] delay ] [ ] [ ] >>
|
|
( 7 ) <a href="#force">force</a> .
|
|
=> 42
|
|
</pre>
|
|
|
|
<!-- lnil description -->
|
|
<a name="lnil">
|
|
<h3>lnil ( -- lcons )</h3>
|
|
<p>Returns a value representing the empty lazy list.</p>
|
|
<pre class="code">
|
|
( 1 ) <a href="#lnil">lnil</a> .
|
|
=> << promise [ ] [ [ ] ] t [ ] >>
|
|
</pre>
|
|
|
|
<!-- lnil description -->
|
|
<a name="lnilp">
|
|
<h3>lnil? ( lcons -- bool )</h3>
|
|
<p>Returns true if the given lazy cons is the value representing
|
|
the empty lazy list.</p>
|
|
<pre class="code">
|
|
( 1 ) <a href="#lnil">lnil</a> <a href="#lnilp">lnil?</a> .
|
|
=> t
|
|
( 2 ) [ 1 ] <a href="#list2llist">list>llist</a> dup <a href="#lnilp">lnil?</a> .
|
|
=> [ ]
|
|
( 3 ) <a href="#lcdr">lcdr</a> <a href="#lnilp">lnil?</a> .
|
|
=> t
|
|
</pre>
|
|
|
|
<!-- lcons description -->
|
|
<a name="lcons">
|
|
<h3>lcons ( car-promise cdr-promise -- lcons )</h3>
|
|
<p>Provides the same effect as 'cons' does for normal lists.
|
|
Both values provided must be promises (ie. expressions that have
|
|
had <a href="#delay">delay</a> called on them).
|
|
</p>
|
|
<p>As the car and cdr passed on the stack are promises, they are not
|
|
evaluated until <a href="#lcar">lcar</a> or <a href="#lcdr">lcdr</a>
|
|
are called on the lazy cons.</p>
|
|
<pre class="code">
|
|
( 1 ) [ "car" ] <a href="#delay">delay</a> [ "cdr" ] <a href="#delay">delay</a> <a href="#lcons">lcons</a> dup .
|
|
=> << promise ... >>
|
|
( 2 ) dup <a href="#lcar">lcar</a> .
|
|
=> "car"
|
|
( 3 ) dup <a href="#lcdr">lcdr</a> .
|
|
=> "cdr"
|
|
</pre>
|
|
|
|
<!-- lunit description -->
|
|
<a name="lunit">
|
|
<h3>lunit ( value-promise -- llist )</h3>
|
|
<p>Provides the same effect as 'unit' does for normal lists. It
|
|
creates a lazy list where the first element is the value given.</p>
|
|
<p>Like <a href="#lcons">lcons</a>, the value on the stack must be
|
|
a promise and is not evaluated until the <a href="#lcar">lcar</a>
|
|
of the list is requested.</a>
|
|
<pre class="code">
|
|
( 1 ) [ 42 ] <a href="#delay">delay</a> <a href="#lunit">lunit</a> dup .
|
|
=> << promise ... >>
|
|
( 2 ) dup <a href="#lcar">lcar</a> .
|
|
=> 42
|
|
( 3 ) dup <a href="#lcdr">lcdr</a> <a href="#lnilp">lnil?</a> .
|
|
=> t
|
|
( 4 ) [ . ] <a href="#leach">leach</a>
|
|
=> 42
|
|
</pre>
|
|
|
|
<!-- lcar description -->
|
|
<a name="lcar">
|
|
<h3>lcar ( lcons -- value )</h3>
|
|
<p>Provides the same effect as 'car' does for normal lists. It
|
|
returns the first element in a lazy cons cell. This will force
|
|
the evaluation of that element.</p>
|
|
<pre class="code">
|
|
( 1 ) [ 42 ] <a href="#delay">delay</a> <a href="#lunit">lunit</a> dup .
|
|
=> << promise ... >>
|
|
( 2 ) <a href="#lcar">lcar</a> .
|
|
=> 42
|
|
</pre>
|
|
|
|
<!-- lcdr description -->
|
|
<a name="lcdr">
|
|
<h3>lcdr ( lcons -- value )</h3>
|
|
<p>Provides the same effect as 'cdr' does for normal lists. It
|
|
returns the second element in a lazy cons cell and forces it. This
|
|
causes that element to be evaluated immediately.</p>
|
|
<pre class="code">
|
|
( 1 ) [ 1 ] <a href="#delay">delay</a> [ 5 6 + ] <a href="#delay">delay</a> <a href="#lcons">lcons</a> dup .
|
|
=> << promise ... >>
|
|
( 2 ) <a href="#lcdr">lcdr</a> .
|
|
=> 11
|
|
</pre>
|
|
|
|
<pre class="code">
|
|
( 1 ) 5 <a href="#lfrom">lfrom</a> dup .
|
|
=> << promise ... >>
|
|
( 2 ) <a href="#lcdr">lcdr</a> dup <a href="#lcar">lcar</a> .
|
|
=> 6
|
|
( 3 ) <a href="#lcdr">lcdr</a> dup <a href="#lcar">lcar</a> .
|
|
=> 7
|
|
( 4 ) <a href="#lcdr">lcdr</a> dup <a href="#lcar">lcar</a> .
|
|
=> 8
|
|
</pre>
|
|
|
|
<!-- lnth description -->
|
|
<a name="lnth">
|
|
<h3>lnth ( n llist -- value )</h3>
|
|
<p>Provides the same effect as 'nth' does for normal lists. It
|
|
returns the nth value in the lazy list. It causes all the values up to
|
|
'n' to be evaluated.</p>
|
|
<pre class="code">
|
|
( 1 ) 1 <a href="#lfrom">lfrom</a> dup .
|
|
=> << promise ... >>
|
|
( 2 ) 5 swap <a href="#lnth">lnth</a> .
|
|
=> 6
|
|
</pre>
|
|
|
|
<!-- luncons description -->
|
|
<a name="luncons">
|
|
<h3>luncons ( lcons -- car cdr )</h3>
|
|
<p>Provides the same effect as 'uncons' does for normal lists. It
|
|
returns the car and cdr of the lazy list.</p>
|
|
<pre class="code">
|
|
( 1 ) [ 5 ] <a href="#delay">delay</a> [ 6 ] <a href="#delay">delay</a> <a href="#lcons">lcons</a> dup .
|
|
=> << promise ... >>
|
|
( 2 ) <a href="#luncons">luncons</a> . .
|
|
=> 6
|
|
5
|
|
</pre>
|
|
|
|
<!-- lmap description -->
|
|
<a name="lmap">
|
|
<h3>lmap ( llist quot -- llist )</h3>
|
|
<p>Lazily maps over a lazy list applying the quotation to each element.
|
|
A new lazy list is returned which contains the results of the
|
|
quotation.</p>
|
|
<p>When intially called nothing in the original lazy list is
|
|
evaluated. Only when <a href="#lcar">lcar</a> is called will the item
|
|
in the list be evaluated and applied to the quotation. Ditto with <a
|
|
href="#lcdr">lcdr</a>, thus allowing infinite lists to be mapped over.</p>
|
|
<pre class="code">
|
|
( 1 ) 1 <a href="#lfrom">lfrom</a>
|
|
=> < infinite list of incrementing numbers >
|
|
( 2 ) [ 2 * ] <a href="#lmap">lmap</a>
|
|
=> < infinite list of numbers incrementing by 2 >
|
|
( 3 ) 5 swap <a href="#ltake">ltake</a> <a href="#llist2list">llist>list</a> .
|
|
=> [ 2 4 6 8 10 ]
|
|
</pre>
|
|
|
|
<!-- lsubset description -->
|
|
<a name="lsubset">
|
|
<h3>lsubset ( llist pred -- llist )</h3>
|
|
<p>Provides the same effect as 'subset' does for normal lists. It
|
|
lazily iterates over a lazy list applying the predicate quotation to each
|
|
element. If that quotation returns true, the element will be included
|
|
in the resulting lazy list. If it is false, the element will be skipped.
|
|
A new lazy list is returned which contains all elements where the
|
|
predicate returned true.</p>
|
|
<p>Like <a href="#lmap">lmap</a>, when initially called no evaluation
|
|
will occur. A lazy list is returned that when values are retrieved
|
|
from in then items are evaluated and checked against the predicate.</p>
|
|
<pre class="code">
|
|
( 1 ) 1 <a href="#lfrom">lfrom</a>
|
|
=> < infinite list of incrementing numbers >
|
|
( 2 ) [ <a href="#primep">prime?</a> ] <a href="#lsubset">lsubset</a>
|
|
=> < infinite list of prime numbers >
|
|
( 3 ) 5 swap <a href="#ltake">ltake</a> <a href="#llist2list">llist>list</a> .
|
|
=> [ 2 3 5 7 11 ]
|
|
</pre>
|
|
|
|
<!-- leach description -->
|
|
<a name="leach">
|
|
<h3>leach ( llist quot -- )</h3>
|
|
<p>Provides the same effect as 'each' does for normal lists. It
|
|
lazily iterates over a lazy list applying the quotation to each
|
|
element. If this operation is applied to an infinite list it will
|
|
never return unless the quotation escapes out by calling a continuation.</p>
|
|
<pre class="code">
|
|
( 1 ) 1 <a href="#lfrom">lfrom</a>
|
|
=> < infinite list of incrementing numbers >
|
|
( 2 ) [ 2 mod 1 = ] <a href="#lsubset">lsubset</a>
|
|
=> < infinite list of odd numbers >
|
|
( 3 ) [ . ] <a href="#leach">leach</a>
|
|
=> 1
|
|
3
|
|
5
|
|
7
|
|
... for ever ...
|
|
</pre>
|
|
|
|
<!-- ltake description -->
|
|
<a name="ltake">
|
|
<h3>ltake ( n llist -- llist )</h3>
|
|
<p>Iterates over the lazy list 'n' times, appending each element to a
|
|
lazy list. This provides a convenient way of getting elements out of
|
|
an infinite lazy list.</p>
|
|
<pre class="code">
|
|
( 1 ) : ones [ 1 ] delay [ ones ] delay <a href="#lcons">lcons</a> ;
|
|
( 2 ) 5 ones <a href="#ltake">ltake</a> <a href="#llist2list">llist>list</a> .
|
|
=> [ 1 1 1 1 1 ]
|
|
</pre>
|
|
|
|
<!-- lappend description -->
|
|
<a name="lappend">
|
|
<h3>lappend ( llist1 llist2 -- llist )</h3>
|
|
<p>Lazily appends two lists together. The actual appending is done
|
|
lazily on iteration rather than immediately so it works very fast no
|
|
matter how large the list.</p>
|
|
<pre class="code">
|
|
( 1 ) [ 1 2 3 ] <a href="#list2llist">list>llist</a> [ 4 5 6 ] <a href="#list2llist">list>llist</a> <a href="#lappend">lappend</a>
|
|
( 2 ) [ . ] <a href="#leach">leach</a>
|
|
=> 1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
6
|
|
</pre>
|
|
|
|
<!-- lappend* description -->
|
|
<a name="lappendstar">
|
|
<h3>lappend* ( llists -- llist )</h3>
|
|
<p>Given a lazy list of lazy lists, concatenate them together in a
|
|
lazy fashion. The actual appending is done lazily on iteration rather
|
|
than immediately so it works very fast no matter how large the lists.</p>
|
|
<pre class="code">
|
|
( 1 ) [ 1 2 3 ] <a href="#list2>llist">list>llist</a>
|
|
( 2 ) [ 4 5 6 ] <a href="#list2llist">list>llist</a>
|
|
( 3 ) [ 7 8 9 ] <a href="#list2llist">list>llist</a>
|
|
( 4 ) 3list <a href="#list2llist">list>llist</a> <a href="#lappendstar">lappend*</a>
|
|
( 5 ) [ . ] <a href="#leach">leach</a>
|
|
=> 1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
6
|
|
7
|
|
8
|
|
9
|
|
</pre>
|
|
|
|
<!-- list>llist description -->
|
|
<a name="list2llist">
|
|
<h3>list>llist ( list -- llist )</h3>
|
|
<p>Converts a normal list into a lazy list. This is done lazily so the
|
|
initial list is not iterated through immediately.</p>
|
|
<pre class="code">
|
|
( 1 ) [ 1 2 3 ] <a href="#list2llist">list>llist</a>
|
|
( 2 ) [ . ] <a href="#leach">leach</a>
|
|
=> 1
|
|
2
|
|
3
|
|
</pre>
|
|
|
|
<p class="footer">
|
|
News and updates to this software can be obtained from the authors
|
|
weblog: <a href="http://radio.weblogs.com/0102385">Chris Double</a>.</p>
|
|
<p id="copyright">Copyright (c) 2004, Chris Double. All Rights Reserved.</p>
|
|
</body> </html>
|