286 lines
15 KiB
HTML
286 lines
15 KiB
HTML
<!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>
|