1
0
Fork 0
cl-sites/www.cs.cmu.edu/Groups/AI/html/cltl/clm/node361.html

287 lines
15 KiB
HTML
Raw Normal View History

2023-10-25 11:23:21 +02:00
<!DOCTYPE HTML PUBLIC "-//W3O//DTD W3 HTML 2.0//EN">
<!Converted with LaTeX2HTML 0.6.5 (Tue Nov 15 1994) by Nikos Drakos (nikos@cbl.leeds.ac.uk), CBLU, University of Leeds >
<HEAD>
<TITLE>A.4. Primitives</TITLE>
</HEAD>
<BODY>
<meta name="description" value=" Primitives">
<meta name="keywords" value="clm">
<meta name="resource-type" value="document">
<meta name="distribution" value="global">
<P>
<b>Common Lisp the Language, 2nd Edition</b>
<BR> <HR><A NAME=tex2html6210 HREF="node362.html"><IMG ALIGN=BOTTOM ALT="next" SRC="icons/next_motif.gif"></A> <A NAME=tex2html6208 HREF="node347.html"><IMG ALIGN=BOTTOM ALT="up" SRC="icons/up_motif.gif"></A> <A NAME=tex2html6204 HREF="node360.html"><IMG ALIGN=BOTTOM ALT="previous" SRC="icons/previous_motif.gif"></A> <A NAME=tex2html6212 HREF="node1.html"><IMG ALIGN=BOTTOM ALT="contents" SRC="icons/contents_motif.gif"></A> <A NAME=tex2html6213 HREF="index.html"><IMG ALIGN=BOTTOM ALT="index" SRC="icons/index_motif.gif"></A> <BR>
<B> Next:</B> <A NAME=tex2html6211 HREF="node362.html"> Generators and Gatherers</A>
<B>Up:</B> <A NAME=tex2html6209 HREF="node347.html"> Series</A>
<B> Previous:</B> <A NAME=tex2html6205 HREF="node360.html"> Declarations</A>
<HR> <P>
<H1><A NAME=SECTION003440000000000000000>A.4. Primitives</A></H1>
<P>
<img align=bottom alt="change_begin" src="gif/change_begin.gif"><br>
A large number of series functions are provided, because there are a
large number of useful operations that can be performed on series.
However, this functionality can be boiled down to a small
number of primitive constructs.
<P>
<tt>collecting-fn</tt> embodies the fundamental idea of series computations
that utilize internal state. It can be used as the basis for defining any
on-line transducer.
<P>
<tt>until</tt> embodies the fundamental idea of producing a series that is
shorter than the shortest input series. In particular, it embodies the
idea of computing a bounded series from non-series inputs. Together with
<tt>collecting-fn</tt>, <tt>until</tt> can be used to define <tt>scan-fn</tt>, which
can be used as the basis for defining all the other scanners.
<P>
<tt>collect-last</tt> embodies the fundamental idea of producing a
non-series value from a series. Together with <tt>collecting-fn</tt>, it
can be used to define <tt>collect-fn</tt>, which (with the occasional
assistance of <tt>until</tt>) can be used as the basis for defining all the other
collectors.
<P>
<tt>producing</tt> embodies the fundamental idea of preorder computation. It
can be used as the basis for defining all the other series functions,
including the off-line transducers.
<P>
In addition to the above, four primitives support
various specialized aspects of series functions. Alterability is
supported by the function <tt>to-alter</tt> and the declaration
<tt>propagate-alterability</tt>. The propagation of type information is
supported by the type specifier <tt>series-element-type</tt>. The best
implementation of certain series functions requires the form
<tt>encapsulated</tt>.
<P>
<BR><b>[Macro]</b><BR>
<tt>producing <i>output-list</i> <i>input-list</i> {<i>declaration</i>}* {<i>form</i>}*</tt><P><tt>producing</tt> computes and returns a group of series and non-series
outputs given a group of series and non-series inputs. The key feature of
<tt>producing</tt> is that some or all of the series inputs and outputs can be
processed in an off-line way. To support this, the processing in the
body (consisting of the <i>forms</i>) is performed from the perspective
of generators and gatherers (see
appendix <A HREF="node362.html#GENERATORS">B</A>). Each series input is converted to a generator
before being used in the body. Each series output is associated with
a gatherer in the body.
<P>
The <i>output-list</i> has the same syntax as the binding list of a
<tt>let</tt>. The names of the variables must be distinct from each other and
from the names of the variables in the <tt>input-list</tt>. If there are <i>n</i>
variables in the <i>output-list</i>, <tt>producing</tt> computes <i>n</i>
outputs. There must be at least one output variable. The variables act as
the names for the outputs and can be used in either of two ways. First, if
an output variable has a value associated with it in the <i>output-list</i>,
then the variable is treated as holding a non-series value. The variable
is initialized to the indicated value and can be used in any way desired in
the body. The eventual output value is whatever value is in the variable
when the execution of the body terminates. Second, if an output variable
does not have a value associated with it in the <i>output-list</i>, the
variable is given as its value a gatherer that collects elements. The only
valid way to use the variable in the body is in a call on <tt>next-out</tt>.
The output returned is a series containing these elements. If the body
never terminates, this series is unbounded.
<P>
The <i>input-list</i> also has the same syntax as the binding list of a
<tt>let</tt>. The names of the variables must be distinct from each other and
the names of the variables in the <i>output-list</i>. The values can be
series or non-series. If the value is not explicitly specified, it
defaults to <tt>nil</tt>. The variables act logically both as inputs and
state variables and can be used in one of two ways. First, if an input
variable is associated with a non-series value, then it is given this value
before the evaluation of the body begins and can be used in any way desired
in the body. Second, if an input variable is associated with a series,
then the variable is given a generator corresponding to this series as its
initial value. The only valid way to use the variable in the body is in a
call on <tt>next-in</tt>.
<P>
There can be declarations at the start of the body. However,
the only declarations allowed are <tt>ignore</tt> declarations, type
declarations, and <tt>propagate-alterability</tt> declarations (see
below). In particular, it is an error for any of the input or output
variables to be special.
<P>
In conception, the body can contain arbitrary Lisp expressions.
After the appropriate generators and gatherers have been set up, the
body is executed until it terminates. If the body never
terminates, the series outputs (if any) are unbounded in length and
the non-series outputs (if any) are never produced.
<P>
Although easy to understand, this view of what can happen in the
body presents severe difficulties when optimizing (and even when
evaluating) series expressions that contain calls on <tt>producing</tt>.
As a result, several limitations are imposed on the form of the
body to simplify the processing required.
<P>
The first limitation is that, exclusive of any declarations, the
body must have the form <tt>(loop (tagbody ...))</tt>. The following
example shows how <tt>producing</tt> could be used to implement a
scanner creating an unbounded series of integers.
<P><pre>
(producing (nums) ((num 0))
(declare (integer num) (type (series integer) nums))
(loop
(tagbody
(setq num (1+ num))
(next-out nums num))))
=> #Z(1 2 3 4 ...)
</pre><P>
<P>
The second limitation is that the form <tt>terminate-producing</tt> must be
used to terminate the execution of the body. Any other method of
terminating the body (with <tt>return</tt>, for example) is an error.
The following example shows how <tt>producing</tt> could be used to
implement the operation of summing a series. The function
<tt>terminate-producing</tt> is used to stop the computation when <tt>numbers</tt>
runs out of elements.
<P><pre>
(producing ((sum 0)) ((numbers #Z(1 2 3)) num)
(loop
(tagbody
(setq num (next-in numbers (terminate-producing)))
(setq sum (+ sum num)))))
=> 6
</pre><P>
<P>
The third limitation is that calls on <tt>next-out</tt> associated with
output variables must appear at top level in the <tt>tagbody</tt> in the
body. They cannot be nested in other forms. In addition, an
output variable can be the destination of at most one call on
<tt>next-out</tt> and if it is the destination of a <tt>next-out</tt>, it cannot
be used in any other way.
<P>
If the call on <tt>next-out</tt> for a given output appears in the
final part of the <tt>tagbody</tt> in the body, after everything
other than other calls on <tt>next-out</tt>, then the output is an
on-line output-a new value is written on every cycle of the
body. Otherwise the output is off-line.
<P>
The following example shows how <tt>producing</tt> could be used to split
a series into two parts. Items are read in one at a time and tested.
Depending on the test, they are written to one of two outputs. Note
the use of labels and branches to keep the calls on
<tt>next-out</tt> at top level. Both outputs are off-line. The first example
above shows an on-line output.
<P><pre>
(producing (items-1 items-2) ((items #Z(1 -2 3 -4)) item)
(loop
(tagbody (setq item (next-in items (terminate-producing)))
(if (not (plusp item)) (go D))
(next-out items-1 item)
(go F)
D (next-out items-2 item)
F )))
=> #Z(1 3) and #Z(-2 -4)
</pre><P>
<P>
The fourth limitation is that the calls on <tt>next-in</tt> associated with an
input variable <tt>v</tt> must appear at top level in the <tt>tagbody</tt> in the
body, nested in assignments of the form
<tt>(setq <i>var</i> (next-in v ...))</tt>. They cannot be nested in other
forms. In addition, an input variable can be the source for at most one
call on <tt>next-in</tt> and if it is the source for a <tt>next-in</tt>, it
cannot be used in any other way.
<P>
If the call on <tt>next-in</tt> for a given input has as its sole
termination action <tt>(terminate-producing)</tt> and
appears in the initial part of the <tt>tagbody</tt> in the body,
before anything other than similar calls on <tt>next-in</tt>, then the
input is an on-line input-a new value is read on every cycle of the
body. Otherwise the input is off-line.
<P>
The example below shows how <tt>producing</tt> could be used to
concatenate two series. To start with, elements are read from the
first input series. When this runs out, a flag is set and reading
begins from the second input. Both inputs are off-line.
(Compare this to the example
above, which shows an on-line input.)
<P><pre>
(producing (items) ((item-1 #Z(1 2))
(item-2 #Z(3 4))
(in-2 nil)
item)
(loop
(tagbody (if in-2 (go D))
(setq item (next-in item-1 (setq in-2 t) (go D)))
(go F)
D (setq item (next-in item-2 (terminate-producing)))
F (next-out items item))))
=> #Z(1 2 3 4)
</pre><P>
<P>
<BR><b>[Macro]</b><BR>
<tt>terminate-producing</tt><P>This form (which takes no arguments) is used to terminate execution of
(the expansion of) the <tt>producing</tt> macro.
<P>
As with the form <tt>go</tt>,
<tt>terminate-producing</tt> does not return any values; rather, control
immediately leaves the current context.
<P>
The form <tt>terminate-producing</tt>
is allowed to appear only in a <tt>producing</tt> body and causes the
termination of the enclosing call on <tt>producing</tt>.
<P>
<BR><b>[Declaration specifier]</b><BR>
<tt>propagate-alterability</tt><P>The declaration specifier
<tt>(propagate-alterability <i>input</i> <i>output</i>)</tt>
indicates that attempts to alter an element of <i>output</i> should be
satisfied by altering the corresponding element of <i>input</i>. (The
corresponding element of <i>input</i> is the one most recently read at the
moment when the output element is written.)
<P>
This declaration may
appear only in a call on <tt>producing</tt>. The <i>input</i> and <i>output</i> arguments must be
an input and an output, respectively, of the <tt>producing</tt> macro. The example below shows how
the propagation of alterability could be supported in a simplified version
of <tt>until</tt>.
<P><pre>
(defun simple-until (bools items)
(declare (optimizable-series-function))
(producing (z) ((x bools) (y items) bool item)
(declare (propagate-alterability y z))
(loop
(tagbody
(setq bool (next-in x (terminate-producing)))
(setq item (next-in y (terminate-producing)))
(if bool (terminate-producing))
(next-out z item)))))
</pre><P>
<P>
<BR><b>[Macro]</b><BR>
<tt>encapsulated <i>encapsulating-fn</i> <i>scanner-or-collector</i></tt><P>Some of the features provided by Common Lisp are supported solely by encapsulating forms.
For example, there is no way to specify a cleanup expression that will always be run, even
when an abort occurs, without using <tt>unwind-protect</tt>. <tt>encapsulated</tt> makes it possible
to take advantage of forms such as <tt>unwind-protect</tt> when defining a series function.
<P>
<tt>encapsulated</tt> specifies a function that places an encapsulating
form around the computation performed by its second argument. The first argument must be a
quoted function that takes a Lisp expression and wraps the appropriate encapsulating form
around it, returning the resulting code.
The second input must be a literal call on <tt>scan-fn</tt>,
<tt>scan-fn-inclusive</tt>, or <tt>collect-fn</tt>. The second argument can count on being evaluated in the
scope of the encapsulating form. The values returned by the second argument are returned as the
values of <tt>encapsulated</tt>. The following shows how
<tt>encapsulated</tt> could be used to define a simplified version of <tt>collect-file</tt>.
<P><pre>
(defun collect-file-wrap (file name body)
`(with-open-file (,file ,name :direction :output) ,body)) <BR><BR>(defmacro simple-collect-file (name items)
(let ((file (gensym)))
`(encapsulated #'(lambda (body)
(collect-file-wrap ',file ',name body))
(collect-fn t #'(lambda () t)
#'(lambda (state item)
(print item ,file)
state)
,items))))
</pre><P>
<img align=bottom alt="change_end" src="gif/change_end.gif">
<P>
<BR> <HR><A NAME=tex2html6210 HREF="node362.html"><IMG ALIGN=BOTTOM ALT="next" SRC="icons/next_motif.gif"></A> <A NAME=tex2html6208 HREF="node347.html"><IMG ALIGN=BOTTOM ALT="up" SRC="icons/up_motif.gif"></A> <A NAME=tex2html6204 HREF="node360.html"><IMG ALIGN=BOTTOM ALT="previous" SRC="icons/previous_motif.gif"></A> <A NAME=tex2html6212 HREF="node1.html"><IMG ALIGN=BOTTOM ALT="contents" SRC="icons/contents_motif.gif"></A> <A NAME=tex2html6213 HREF="index.html"><IMG ALIGN=BOTTOM ALT="index" SRC="icons/index_motif.gif"></A> <BR>
<B> Next:</B> <A NAME=tex2html6211 HREF="node362.html"> Generators and Gatherers</A>
<B>Up:</B> <A NAME=tex2html6209 HREF="node347.html"> Series</A>
<B> Previous:</B> <A NAME=tex2html6205 HREF="node360.html"> Declarations</A>
<HR> <P>
<HR>
<P><ADDRESS>
AI.Repository@cs.cmu.edu
</ADDRESS>
</BODY>