rlm@2
|
1 <?xml version="1.0" encoding="utf-8"?>
|
rlm@2
|
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
rlm@2
|
3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
rlm@2
|
4 <html xmlns="http://www.w3.org/1999/xhtml"
|
rlm@2
|
5 lang="en" xml:lang="en">
|
rlm@2
|
6 <head>
|
rlm@2
|
7 <title>LAMBDA: The Ultimate Imperative</title>
|
rlm@2
|
8 <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
|
rlm@2
|
9 <meta name="generator" content="Org-mode"/>
|
rlm@2
|
10 <meta name="generated" content="2011-07-15 02:49:04 EDT"/>
|
rlm@2
|
11 <meta name="author" content="Guy Lewis Steele Jr. and Gerald Jay Sussman"/>
|
rlm@2
|
12 <meta name="description" content=""/>
|
rlm@2
|
13 <meta name="keywords" content=""/>
|
rlm@2
|
14 <style type="text/css">
|
rlm@2
|
15 <!--/*--><![CDATA[/*><!--*/
|
rlm@2
|
16 html { font-family: Times, serif; font-size: 12pt; }
|
rlm@2
|
17 .title { text-align: center; }
|
rlm@2
|
18 .todo { color: red; }
|
rlm@2
|
19 .done { color: green; }
|
rlm@2
|
20 .tag { background-color: #add8e6; font-weight:normal }
|
rlm@2
|
21 .target { }
|
rlm@2
|
22 .timestamp { color: #bebebe; }
|
rlm@2
|
23 .timestamp-kwd { color: #5f9ea0; }
|
rlm@2
|
24 .right {margin-left:auto; margin-right:0px; text-align:right;}
|
rlm@2
|
25 .left {margin-left:0px; margin-right:auto; text-align:left;}
|
rlm@2
|
26 .center {margin-left:auto; margin-right:auto; text-align:center;}
|
rlm@2
|
27 p.verse { margin-left: 3% }
|
rlm@2
|
28 pre {
|
rlm@2
|
29 border: 1pt solid #AEBDCC;
|
rlm@2
|
30 background-color: #F3F5F7;
|
rlm@2
|
31 padding: 5pt;
|
rlm@2
|
32 font-family: courier, monospace;
|
rlm@2
|
33 font-size: 90%;
|
rlm@2
|
34 overflow:auto;
|
rlm@2
|
35 }
|
rlm@2
|
36 table { border-collapse: collapse; }
|
rlm@2
|
37 td, th { vertical-align: top; }
|
rlm@2
|
38 th.right { text-align:center; }
|
rlm@2
|
39 th.left { text-align:center; }
|
rlm@2
|
40 th.center { text-align:center; }
|
rlm@2
|
41 td.right { text-align:right; }
|
rlm@2
|
42 td.left { text-align:left; }
|
rlm@2
|
43 td.center { text-align:center; }
|
rlm@2
|
44 dt { font-weight: bold; }
|
rlm@2
|
45 div.figure { padding: 0.5em; }
|
rlm@2
|
46 div.figure p { text-align: center; }
|
rlm@2
|
47 textarea { overflow-x: auto; }
|
rlm@2
|
48 .linenr { font-size:smaller }
|
rlm@2
|
49 .code-highlighted {background-color:#ffff00;}
|
rlm@2
|
50 .org-info-js_info-navigation { border-style:none; }
|
rlm@2
|
51 #org-info-js_console-label { font-size:10px; font-weight:bold;
|
rlm@2
|
52 white-space:nowrap; }
|
rlm@2
|
53 .org-info-js_search-highlight {background-color:#ffff00; color:#000000;
|
rlm@2
|
54 font-weight:bold; }
|
rlm@2
|
55 /*]]>*/-->
|
rlm@2
|
56 </style>
|
rlm@2
|
57 <script type="text/javascript">
|
rlm@2
|
58 <!--/*--><![CDATA[/*><!--*/
|
rlm@2
|
59 function CodeHighlightOn(elem, id)
|
rlm@2
|
60 {
|
rlm@2
|
61 var target = document.getElementById(id);
|
rlm@2
|
62 if(null != target) {
|
rlm@2
|
63 elem.cacheClassElem = elem.className;
|
rlm@2
|
64 elem.cacheClassTarget = target.className;
|
rlm@2
|
65 target.className = "code-highlighted";
|
rlm@2
|
66 elem.className = "code-highlighted";
|
rlm@2
|
67 }
|
rlm@2
|
68 }
|
rlm@2
|
69 function CodeHighlightOff(elem, id)
|
rlm@2
|
70 {
|
rlm@2
|
71 var target = document.getElementById(id);
|
rlm@2
|
72 if(elem.cacheClassElem)
|
rlm@2
|
73 elem.className = elem.cacheClassElem;
|
rlm@2
|
74 if(elem.cacheClassTarget)
|
rlm@2
|
75 target.className = elem.cacheClassTarget;
|
rlm@2
|
76 }
|
rlm@2
|
77 /*]]>*///-->
|
rlm@2
|
78 </script>
|
rlm@2
|
79 <script type="text/javascript" src="http://orgmode.org/mathjax/MathJax.js">
|
rlm@2
|
80 <!--/*--><![CDATA[/*><!--*/
|
rlm@2
|
81 MathJax.Hub.Config({
|
rlm@2
|
82 // Only one of the two following lines, depending on user settings
|
rlm@2
|
83 // First allows browser-native MathML display, second forces HTML/CSS
|
rlm@2
|
84 // config: ["MMLorHTML.js"], jax: ["input/TeX"],
|
rlm@2
|
85 jax: ["input/TeX", "output/HTML-CSS"],
|
rlm@2
|
86 extensions: ["tex2jax.js","TeX/AMSmath.js","TeX/AMSsymbols.js",
|
rlm@2
|
87 "TeX/noUndefined.js"],
|
rlm@2
|
88 tex2jax: {
|
rlm@2
|
89 inlineMath: [ ["\\(","\\)"] ],
|
rlm@2
|
90 displayMath: [ ['$$','$$'], ["\\[","\\]"], ["\\begin{displaymath}","\\end{displaymath}"] ],
|
rlm@2
|
91 skipTags: ["script","noscript","style","textarea","pre","code"],
|
rlm@2
|
92 ignoreClass: "tex2jax_ignore",
|
rlm@2
|
93 processEscapes: false,
|
rlm@2
|
94 processEnvironments: true,
|
rlm@2
|
95 preview: "TeX"
|
rlm@2
|
96 },
|
rlm@2
|
97 showProcessingMessages: true,
|
rlm@2
|
98 displayAlign: "center",
|
rlm@2
|
99 displayIndent: "2em",
|
rlm@2
|
100
|
rlm@2
|
101 "HTML-CSS": {
|
rlm@2
|
102 scale: 100,
|
rlm@2
|
103 availableFonts: ["STIX","TeX"],
|
rlm@2
|
104 preferredFont: "TeX",
|
rlm@2
|
105 webFont: "TeX",
|
rlm@2
|
106 imageFont: "TeX",
|
rlm@2
|
107 showMathMenu: true,
|
rlm@2
|
108 },
|
rlm@2
|
109 MMLorHTML: {
|
rlm@2
|
110 prefer: {
|
rlm@2
|
111 MSIE: "MML",
|
rlm@2
|
112 Firefox: "MML",
|
rlm@2
|
113 Opera: "HTML",
|
rlm@2
|
114 other: "HTML"
|
rlm@2
|
115 }
|
rlm@2
|
116 }
|
rlm@2
|
117 });
|
rlm@2
|
118 /*]]>*///-->
|
rlm@2
|
119 </script>
|
rlm@2
|
120 </head>
|
rlm@2
|
121 <body>
|
rlm@2
|
122
|
rlm@2
|
123 <div id="content">
|
rlm@2
|
124
|
rlm@2
|
125
|
rlm@2
|
126
|
rlm@2
|
127 <div id="table-of-contents">
|
rlm@2
|
128 <h2>Table of Contents</h2>
|
rlm@2
|
129 <div id="text-table-of-contents">
|
rlm@2
|
130 <ul>
|
rlm@2
|
131 <li><a href="#sec-1">1 Abstract </a></li>
|
rlm@2
|
132 <li><a href="#sec-2">2 Introduction </a>
|
rlm@2
|
133 <ul>
|
rlm@2
|
134 <li><a href="#sec-2-1">2.1 Simple Loops </a>
|
rlm@2
|
135 <ul>
|
rlm@2
|
136 <li><a href="#sec-2-1-1">2.1.1 Simple Recursion </a></li>
|
rlm@2
|
137 <li><a href="#sec-2-1-2">2.1.2 Iteration </a></li>
|
rlm@2
|
138 </ul></li>
|
rlm@2
|
139 </ul>
|
rlm@2
|
140 </li>
|
rlm@2
|
141 <li><a href="#sec-3">3 Imperative Programming </a>
|
rlm@2
|
142 <ul>
|
rlm@2
|
143 <li><a href="#sec-3-1">3.1 Compound Statements </a></li>
|
rlm@2
|
144 <li><a href="#sec-3-2">3.2 2.2. The G0 TO Statement </a></li>
|
rlm@2
|
145 <li><a href="#sec-3-3">3.3 2.3. Simple Assignment </a></li>
|
rlm@2
|
146 <li><a href="#sec-3-4">3.4 Compound Expressions ' </a></li>
|
rlm@2
|
147 </ul>
|
rlm@2
|
148 </li>
|
rlm@2
|
149 <li><a href="#sec-4">4 Continuations </a>
|
rlm@2
|
150 <ul>
|
rlm@2
|
151 <li><a href="#sec-4-1">4.1 Continuation-Passing Recursion </a></li>
|
rlm@2
|
152 <li><a href="#sec-4-2">4.2 Escape Expressions </a></li>
|
rlm@2
|
153 </ul>
|
rlm@2
|
154 </li>
|
rlm@2
|
155 </ul>
|
rlm@2
|
156 </div>
|
rlm@2
|
157 </div>
|
rlm@2
|
158
|
rlm@2
|
159 <div id="outline-container-1" class="outline-2">
|
rlm@2
|
160 <h2 id="sec-1"><span class="section-number-2">1</span> Abstract </h2>
|
rlm@2
|
161 <div class="outline-text-2" id="text-1">
|
rlm@2
|
162
|
rlm@2
|
163
|
rlm@2
|
164 <p>
|
rlm@2
|
165 We demonstrate how to model the following common programming constructs in
|
rlm@2
|
166 terms of an applicative order language similar to LISP:
|
rlm@2
|
167 </p><ul>
|
rlm@2
|
168 <li>Simple Recursion
|
rlm@2
|
169 </li>
|
rlm@2
|
170 <li>Iteration
|
rlm@2
|
171 </li>
|
rlm@2
|
172 <li>Compound Statements and Expressions
|
rlm@2
|
173 </li>
|
rlm@2
|
174 <li>GO TO and Assignment
|
rlm@2
|
175 </li>
|
rlm@2
|
176 <li>Continuation—Passing
|
rlm@2
|
177 </li>
|
rlm@2
|
178 <li>Escape Expressions
|
rlm@2
|
179 </li>
|
rlm@2
|
180 <li>Fluid Variables
|
rlm@2
|
181 </li>
|
rlm@2
|
182 <li>Call by Name, Call by Need, and Call by Reference
|
rlm@2
|
183 </li>
|
rlm@2
|
184 </ul>
|
rlm@2
|
185
|
rlm@2
|
186 <p>The models require only (possibly self-referent) lambda application,
|
rlm@2
|
187 conditionals, and (rarely) assignment. No complex data structures such as
|
rlm@2
|
188 stacks are used. The models are transparent, involving only local syntactic
|
rlm@2
|
189 transformations.
|
rlm@2
|
190 Some of these models, such as those for GO TO and assignment, are already well
|
rlm@2
|
191 known, and appear in the work of Landin, Reynolds, and others. The models for
|
rlm@2
|
192 escape expressions, fluid variables, and call by need with side effects are
|
rlm@2
|
193 new. This paper is partly tutorial in intent, gathering all the models
|
rlm@2
|
194 together for purposes of context.
|
rlm@2
|
195 This report describes research done at the Artificial Intelligence Laboratory
|
rlm@2
|
196 of the Massachusetts Institute of Teehnology. Support for the laboratory's
|
rlm@2
|
197 artificial intelligence research is provided in part by the Advanced Research
|
rlm@2
|
198 Projects Agency of the Department of Defense under Office of Naval Research
|
rlm@2
|
199 contract N000l4-75-C-0643.
|
rlm@2
|
200 </p>
|
rlm@2
|
201 </div>
|
rlm@2
|
202
|
rlm@2
|
203 </div>
|
rlm@2
|
204
|
rlm@2
|
205 <div id="outline-container-2" class="outline-2">
|
rlm@2
|
206 <h2 id="sec-2"><span class="section-number-2">2</span> Introduction </h2>
|
rlm@2
|
207 <div class="outline-text-2" id="text-2">
|
rlm@2
|
208
|
rlm@2
|
209
|
rlm@2
|
210 <p>
|
rlm@2
|
211 We catalogue a number of common programming constructs. For each
|
rlm@2
|
212 construct we examine "typical" usage in well-known programming languages, and
|
rlm@2
|
213 then capture the essence of the semantics of the construct in terms of a
|
rlm@2
|
214 common meta-language.
|
rlm@2
|
215 The lambda calculus {Note Alonzowins} is often used as such a meta-
|
rlm@2
|
216 language. Lambda calculus offers clean semantics, but it is clumsy because it
|
rlm@2
|
217 was designed to be a minimal language rather than a convenient one. All
|
rlm@2
|
218 lambda calculus "functions" must take exactly one "argument"; the only "data
|
rlm@2
|
219 type" is lambda expressions; and the only "primitive operation‘ is variable‘
|
rlm@2
|
220 substitution. While its utter simplicity makes lambda calculus ideal for
|
rlm@2
|
221 logicians, it is too primitive for use by programmers. The meta-language we
|
rlm@2
|
222 use is a programming language called SCHEME {Note Schemepaper) which is based
|
rlm@2
|
223 on lambda calculus.
|
rlm@2
|
224 SCHEME is a dialect of LISP. [McCarthy 62] It is an expression-
|
rlm@2
|
225 oriented, applicative order, interpreter-based language which allows one to
|
rlm@2
|
226 manipulate programs as data. It differs from most current dialects of LISP in
|
rlm@2
|
227 that it closes all lambda expressions in the environment of their definition
|
rlm@2
|
228 or declaration, rather than in the execution environment. {Note Closures}
|
rlm@2
|
229 This preserves the substitution semantics of lambda calculus, and has the
|
rlm@2
|
230 consequence that all variables are lexically scoped, as in ALGOL. [Naur 63]
|
rlm@2
|
231 Another difference is that SCHEME is implemented in such a way that tail-
|
rlm@2
|
232 recursions execute without net growth of the interpreter stack. {Note
|
rlm@2
|
233 Schemenote} We have chosen to use LISP syntax rather than, say, ALGOL syntax
|
rlm@2
|
234 because we want to treat programs as data for the purpose of describing
|
rlm@2
|
235 transformations on the code. LISP supplies names for the parts of an
|
rlm@2
|
236 executable expression and standard operators for constructing expressions and
|
rlm@2
|
237 extracting their components. The use of LISP syntax makes the structure of
|
rlm@2
|
238 such expressions manifest. We use ALGOL as an expository language, because it
|
rlm@2
|
239 is familiar to many people, but ALGOL is not sufficiently powerful to express
|
rlm@2
|
240 the necessary concepts; in particular, it does not allow functions to return
|
rlm@2
|
241 functions as values. we are thus forced to use a dialect of LISP in many
|
rlm@2
|
242 cases.
|
rlm@2
|
243 We will consider various complex programming language constructs and
|
rlm@2
|
244 show how to model them in terms of only a few simple ones. As far as possible
|
rlm@2
|
245 we will use only three control constructs from SCHEME: LAMBDA expressions, as
|
rlm@2
|
246 in LISP, which are Just functions with lexically scoped free variables;
|
rlm@2
|
247 LABELS, which allows declaration of mutually recursive procedures (Note
|
rlm@2
|
248 Labelsdef}; and IF, a primitive conditional expression. For more complex
|
rlm@2
|
249 modelling we will introduce an assignment primitive (ASET).i We will freely
|
rlm@2
|
250 assume the existence of other comon primitives, such as arithmetic functions.
|
rlm@2
|
251 The constructs we will examine are divided into four broad classes.
|
rlm@2
|
252 The first is sfinph?Lo0pl; this contains simple recursions and iterations, and
|
rlm@2
|
253 an introduction to the notion of continuations. The second is hmponflivo
|
rlm@2
|
254 Connrucls; this includes compound statements, G0 T0, and simple variable
|
rlm@2
|
255 assignments. The third is continuations, which encompasses the distinction between statements and expressions, escape operators (such as Landin's J-
|
rlm@2
|
256 operator [Landin 65] and Reynold's escape expression [Reynolds 72]). and fluid
|
rlm@2
|
257 (dynamically bound) variables. The fourth is Parameter Passing Mechanisms, such
|
rlm@2
|
258 as ALGOL call—by-name and FORTRAN call-by-location.
|
rlm@2
|
259 Some of the models presented here are already well-known, particularly
|
rlm@2
|
260 those for G0 T0 and assignment. [McCarthy 60] [Landin 65] [Reynolds 72]
|
rlm@2
|
261 Those for escape operators, fluid variables, and call-by-need with side
|
rlm@2
|
262 effects are new.
|
rlm@2
|
263 </p>
|
rlm@2
|
264 </div>
|
rlm@2
|
265
|
rlm@2
|
266 <div id="outline-container-2-1" class="outline-3">
|
rlm@2
|
267 <h3 id="sec-2-1"><span class="section-number-3">2.1</span> Simple Loops </h3>
|
rlm@2
|
268 <div class="outline-text-3" id="text-2-1">
|
rlm@2
|
269
|
rlm@2
|
270 <p>By <i>simple loops</i> we mean constructs which enable programs to execute the
|
rlm@2
|
271 same piece of code repeatedly in a controlled manner. Variables may be made
|
rlm@2
|
272 to take on different values during each repetition, and the number of
|
rlm@2
|
273 repetitions may depend on data given to the program.
|
rlm@2
|
274 </p>
|
rlm@2
|
275 </div>
|
rlm@2
|
276
|
rlm@2
|
277 <div id="outline-container-2-1-1" class="outline-4">
|
rlm@2
|
278 <h4 id="sec-2-1-1"><span class="section-number-4">2.1.1</span> Simple Recursion </h4>
|
rlm@2
|
279 <div class="outline-text-4" id="text-2-1-1">
|
rlm@2
|
280
|
rlm@2
|
281 <p>One of the easiest ways to produce a looping control structure is to
|
rlm@2
|
282 use a recursive function, one which calls itself to perform a subcomputation.
|
rlm@2
|
283 For example, the familiar factorial function may be written recursively in
|
rlm@2
|
284 ALGOL: '
|
rlm@2
|
285 </p>
|
rlm@2
|
286
|
rlm@2
|
287
|
rlm@2
|
288 <pre class="src src-algol">integer procedure fact(n) value n: integer n:
|
rlm@2
|
289 fact := if n=0 then 1 else n*fact(n-1);
|
rlm@2
|
290
|
rlm@2
|
291 </pre>
|
rlm@2
|
292
|
rlm@2
|
293
|
rlm@2
|
294
|
rlm@2
|
295
|
rlm@2
|
296 <p>
|
rlm@2
|
297 The invocation <code>fact(n)</code> computes the product of the integers from 1 to n using
|
rlm@2
|
298 the identity n!=n(n-1)! (n>0). If \(n\) is zero, 1 is returned; otherwise <code>fact</code>:
|
rlm@2
|
299 calls itself recursively to compute \((n-1)!\) , then multiplies the result by \(n\)
|
rlm@2
|
300 and returns it.
|
rlm@2
|
301 </p>
|
rlm@2
|
302 <p>
|
rlm@2
|
303 This same function may be written in Clojure as follows:
|
rlm@2
|
304 </p>
|
rlm@2
|
305
|
rlm@2
|
306
|
rlm@2
|
307 <pre class="src src-clojure">(<span style="color: #f0dfaf; font-weight: bold;">ns</span> categorical.imperative)
|
rlm@2
|
308 (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">fact</span>[n]
|
rlm@2
|
309 (<span style="color: #f0dfaf; font-weight: bold;">if</span> (<span style="color: #8cd0d3;">=</span> n 0) 1 (<span style="color: #8cd0d3;">*</span> n (fact (<span style="color: #8cd0d3;">dec</span> n))))
|
rlm@2
|
310 )
|
rlm@2
|
311
|
rlm@2
|
312 </pre>
|
rlm@2
|
313
|
rlm@2
|
314
|
rlm@2
|
315
|
rlm@2
|
316
|
rlm@2
|
317
|
rlm@2
|
318 <p>
|
rlm@2
|
319 Clojure does not require an assignment to the ``variable'' fan: to return a value
|
rlm@2
|
320 as ALGOL does. The IF primitive is the ALGOL if-then-else rendered in LISP
|
rlm@2
|
321 syntax. Note that the arithmetic primitives are prefix operators in SCHEME.
|
rlm@2
|
322 </p>
|
rlm@2
|
323 </div>
|
rlm@2
|
324
|
rlm@2
|
325 </div>
|
rlm@2
|
326
|
rlm@2
|
327 <div id="outline-container-2-1-2" class="outline-4">
|
rlm@2
|
328 <h4 id="sec-2-1-2"><span class="section-number-4">2.1.2</span> Iteration </h4>
|
rlm@2
|
329 <div class="outline-text-4" id="text-2-1-2">
|
rlm@2
|
330
|
rlm@2
|
331 <p>There are many other ways to compute factorial. One important way is
|
rlm@2
|
332 through the use of <i>iteration</i>.
|
rlm@2
|
333 A comon iterative construct is the DO loop. The most general form we
|
rlm@2
|
334 have seen in any programming language is the MacLISP DO [Moon 74]. It permits
|
rlm@2
|
335 the simultaneous initialization of any number of control variables and the
|
rlm@2
|
336 simultaneous stepping of these variables by arbitrary functions at each
|
rlm@2
|
337 iteration step. The loop is terminated by an arbitrary predicate, and an
|
rlm@2
|
338 arbitrary value may be returned. The DO loop may have a body, a series of
|
rlm@2
|
339 expressions executed for effect on each iteration. A version of the MacLISP
|
rlm@2
|
340 DO construct has been adopted in SCHEME.
|
rlm@2
|
341 </p>
|
rlm@2
|
342 <p>
|
rlm@2
|
343 The general form of a SCHEME DO is:
|
rlm@2
|
344 </p>
|
rlm@2
|
345
|
rlm@2
|
346
|
rlm@2
|
347 <pre class="src src-nothing">(DO ((<var1> (init1> <stepl>)
|
rlm@2
|
348 ((var2> <init2> <step2>)
|
rlm@2
|
349 (<varn> <intn> (stepn>))
|
rlm@2
|
350 (<pred> (value>)
|
rlm@2
|
351 (optional body>)
|
rlm@2
|
352
|
rlm@2
|
353 </pre>
|
rlm@2
|
354
|
rlm@2
|
355
|
rlm@2
|
356
|
rlm@2
|
357 <p>
|
rlm@2
|
358 The semantics of this are that the variables are bound and initialized to the
|
rlm@2
|
359 values of the <initi> expressions, which must all be evaluated in the
|
rlm@2
|
360 environment outside the D0; then the predicate <pred> is evaluated in the new
|
rlm@2
|
361 environment, and if TRUE, the (value) is evaluated and returned. Otherwise
|
rlm@2
|
362 the (optional body) is evaluated, then each of the steppers <stepi> is
|
rlm@2
|
363 evaluated in the current environment, all the variables made to have the
|
rlm@2
|
364 results as their values, the predicate evaluated again, and so on.
|
rlm@2
|
365 Using D0 loops in both ALGOL and SCHEME, we may express FACT by means
|
rlm@2
|
366 of iteration.
|
rlm@2
|
367 </p>
|
rlm@2
|
368
|
rlm@2
|
369
|
rlm@2
|
370 <pre class="src src-algol">integer procedure fact(n); value n; integer n:
|
rlm@2
|
371 begin
|
rlm@2
|
372 integer m, ans;
|
rlm@2
|
373 ans := 1;
|
rlm@2
|
374 for m := n step -l until 0 do ans := m*ans;
|
rlm@2
|
375 fact := ans;
|
rlm@2
|
376 end;
|
rlm@2
|
377
|
rlm@2
|
378 </pre>
|
rlm@2
|
379
|
rlm@2
|
380
|
rlm@2
|
381
|
rlm@2
|
382
|
rlm@2
|
383
|
rlm@2
|
384 <pre class="src src-clojure">(<span style="color: #f0dfaf; font-weight: bold;">in-ns</span> 'categorical.imperative)
|
rlm@2
|
385 (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">fact-do</span>[n]
|
rlm@2
|
386 )
|
rlm@2
|
387
|
rlm@2
|
388 </pre>
|
rlm@2
|
389
|
rlm@2
|
390
|
rlm@2
|
391
|
rlm@2
|
392
|
rlm@2
|
393 <p>
|
rlm@2
|
394 Note that the SCHEME D0 loop in FACT has no body – the stepping functions do
|
rlm@2
|
395 all the work. The ALGOL DO loop has an assignment in its body; because an
|
rlm@2
|
396 ALGOL DO loop can step only one variable, we need the assignment to step the
|
rlm@2
|
397 the variable "manually'.
|
rlm@2
|
398 In reality the SCHEME DO construct is not a primitive; it is a macro
|
rlm@2
|
399 which expands into a function which performs the iteration by tail—recursion.
|
rlm@2
|
400 Consider the following definition of FACT in SCHEME. Although it appears to
|
rlm@2
|
401 be recursive, since it "calls itself", it is entirely equivalent to the DO
|
rlm@2
|
402 loop given above, for it is the code that the DO macro expands into! It
|
rlm@2
|
403 captures the essence of our intuitive notion of iteration, because execution
|
rlm@2
|
404 of this program will not produce internal structures (e.g. stacks or variable
|
rlm@2
|
405 bindings) which increase in size with the number of iteration steps.
|
rlm@2
|
406 </p>
|
rlm@2
|
407
|
rlm@2
|
408
|
rlm@2
|
409
|
rlm@2
|
410 <pre class="src src-clojure">(<span style="color: #f0dfaf; font-weight: bold;">in-ns</span> 'categorical.imperative)
|
rlm@2
|
411 (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">fact-do-expand</span>[n]
|
rlm@2
|
412 (<span style="color: #f0dfaf; font-weight: bold;">let</span> [fact1
|
rlm@2
|
413 (<span style="color: #8cd0d3;">fn</span>[m ans]
|
rlm@2
|
414 (<span style="color: #f0dfaf; font-weight: bold;">if</span> (zero? m) ans
|
rlm@2
|
415 (<span style="color: #f0dfaf; font-weight: bold;">recur</span> (<span style="color: #8cd0d3;">dec</span> m) (<span style="color: #8cd0d3;">*</span> m ans))))]
|
rlm@2
|
416 (fact1 n 1)))
|
rlm@2
|
417
|
rlm@2
|
418 </pre>
|
rlm@2
|
419
|
rlm@2
|
420
|
rlm@2
|
421
|
rlm@2
|
422
|
rlm@2
|
423 <p>
|
rlm@2
|
424 From this we can infer a general way to express iterations in SCHEME in
|
rlm@2
|
425 a manner isomorphic to the HacLISP D0. The expansion of the general D0 loop
|
rlm@2
|
426 </p>
|
rlm@2
|
427
|
rlm@2
|
428
|
rlm@2
|
429 <pre class="src src-nothing">(DO ((<varl> <init1> <step1>)
|
rlm@2
|
430 (<var2> (init2) <step2>)
|
rlm@2
|
431 ...
|
rlm@2
|
432 (<varn> <initn> <stepn>))
|
rlm@2
|
433 (<pred> <va1ue>)
|
rlm@2
|
434 <body>)
|
rlm@2
|
435
|
rlm@2
|
436 </pre>
|
rlm@2
|
437
|
rlm@2
|
438
|
rlm@2
|
439
|
rlm@2
|
440 <p>
|
rlm@2
|
441 is this:
|
rlm@2
|
442 </p>
|
rlm@2
|
443
|
rlm@2
|
444
|
rlm@2
|
445 <pre class="src src-nothing">(let [doloop
|
rlm@2
|
446 (fn [dummy <var1> <var2> ... <varn>)
|
rlm@2
|
447 (if <pred> <value>
|
rlm@2
|
448 (recur <body> <step1> <step2> ... <stepn>)))]
|
rlm@2
|
449
|
rlm@2
|
450 (doloop nil <init1> <init2> ... <initn>))
|
rlm@2
|
451
|
rlm@2
|
452 </pre>
|
rlm@2
|
453
|
rlm@2
|
454
|
rlm@2
|
455
|
rlm@2
|
456 <p>
|
rlm@2
|
457 The identifiers <code>doloop</code> and <code>dummy</code> are chosen so as not to conflict with any
|
rlm@2
|
458 other identifiers in the program.
|
rlm@2
|
459 Note that, unlike most implementations of D0, there are no side effects
|
rlm@2
|
460 in the steppings of the iteration variables. D0 loops are usually modelled
|
rlm@2
|
461 using assignment statements. For example:
|
rlm@2
|
462 </p>
|
rlm@2
|
463
|
rlm@2
|
464
|
rlm@2
|
465 <pre class="src src-nothing">for r :1 0 step b until c do <statement>;
|
rlm@2
|
466
|
rlm@2
|
467 </pre>
|
rlm@2
|
468
|
rlm@2
|
469
|
rlm@2
|
470
|
rlm@2
|
471
|
rlm@2
|
472 <p>
|
rlm@2
|
473 can be modelled as follows: [Naur 63]
|
rlm@2
|
474 </p>
|
rlm@2
|
475
|
rlm@2
|
476
|
rlm@2
|
477 <pre class="src src-nothing">begin
|
rlm@2
|
478 x := a;
|
rlm@2
|
479 L: if (x-c)*sign(n) > 0 then go to Endloop;
|
rlm@2
|
480 <statement>;
|
rlm@2
|
481 x := x+b;
|
rlm@2
|
482 go to L:
|
rlm@2
|
483 Endloop:
|
rlm@2
|
484 end;
|
rlm@2
|
485
|
rlm@2
|
486 </pre>
|
rlm@2
|
487
|
rlm@2
|
488
|
rlm@2
|
489
|
rlm@2
|
490 <p>
|
rlm@2
|
491 Later we will see how such assignment statements can in general be
|
rlm@2
|
492 modelled without using side effects.
|
rlm@2
|
493 </p>
|
rlm@2
|
494 </div>
|
rlm@2
|
495 </div>
|
rlm@2
|
496 </div>
|
rlm@2
|
497
|
rlm@2
|
498 </div>
|
rlm@2
|
499
|
rlm@2
|
500 <div id="outline-container-3" class="outline-2">
|
rlm@2
|
501 <h2 id="sec-3"><span class="section-number-2">3</span> Imperative Programming </h2>
|
rlm@2
|
502 <div class="outline-text-2" id="text-3">
|
rlm@2
|
503
|
rlm@2
|
504 <p>Lambda calculus (and related languages, such as ``pure LISP'') is often
|
rlm@2
|
505 used for modelling the applicative constructs of programming languages.
|
rlm@2
|
506 However, they are generally thought of as inappropriate for modelling
|
rlm@2
|
507 imperative constructs. In this section we show how imperative constructs may
|
rlm@2
|
508 be modelled by applicative SCHEME constructs.
|
rlm@2
|
509 </p>
|
rlm@2
|
510 </div>
|
rlm@2
|
511
|
rlm@2
|
512 <div id="outline-container-3-1" class="outline-3">
|
rlm@2
|
513 <h3 id="sec-3-1"><span class="section-number-3">3.1</span> Compound Statements </h3>
|
rlm@2
|
514 <div class="outline-text-3" id="text-3-1">
|
rlm@2
|
515
|
rlm@2
|
516 <p>The simplest kind of imperative construct is the statement sequencer,
|
rlm@2
|
517 for example the compound statement in ALGOL:
|
rlm@2
|
518 </p>
|
rlm@2
|
519
|
rlm@2
|
520
|
rlm@2
|
521 <pre class="src src-algol">begin
|
rlm@2
|
522 S1;
|
rlm@2
|
523 S2;
|
rlm@2
|
524 end
|
rlm@2
|
525
|
rlm@2
|
526 </pre>
|
rlm@2
|
527
|
rlm@2
|
528
|
rlm@2
|
529
|
rlm@2
|
530
|
rlm@2
|
531 <p>
|
rlm@2
|
532 This construct has two interesting properties:
|
rlm@2
|
533 </p><ul>
|
rlm@2
|
534 <li>(1) It performs statement S1 before S2, and so may be used for
|
rlm@2
|
535 sequencing.
|
rlm@2
|
536 </li>
|
rlm@2
|
537 <li>(2) S1 is useful only for its side effects. (In ALGOL, S2 must also
|
rlm@2
|
538 be a statement, and so is also useful only for side effects, but
|
rlm@2
|
539 other languages have compound expressions containing a statement
|
rlm@2
|
540 followed by an expression.)
|
rlm@2
|
541 </li>
|
rlm@2
|
542 </ul>
|
rlm@2
|
543
|
rlm@2
|
544
|
rlm@2
|
545 <p>
|
rlm@2
|
546 The ALGOL compound statement may actually contain any number of statements,
|
rlm@2
|
547 but such statements can be expressed as a series of nested two-statement
|
rlm@2
|
548 compounds. That is:
|
rlm@2
|
549 </p>
|
rlm@2
|
550
|
rlm@2
|
551
|
rlm@2
|
552 <pre class="src src-algol">begin
|
rlm@2
|
553 S1;
|
rlm@2
|
554 S2;
|
rlm@2
|
555 ...
|
rlm@2
|
556 Sn-1;
|
rlm@2
|
557 Sn;
|
rlm@2
|
558 end
|
rlm@2
|
559
|
rlm@2
|
560 </pre>
|
rlm@2
|
561
|
rlm@2
|
562
|
rlm@2
|
563
|
rlm@2
|
564 <p>
|
rlm@2
|
565 is equivalent to:
|
rlm@2
|
566 </p>
|
rlm@2
|
567
|
rlm@2
|
568
|
rlm@2
|
569
|
rlm@2
|
570 <pre class="src src-algol">begin
|
rlm@2
|
571 S1;
|
rlm@2
|
572 begin
|
rlm@2
|
573 S2;
|
rlm@2
|
574 begin
|
rlm@2
|
575 ...
|
rlm@2
|
576
|
rlm@2
|
577 begin
|
rlm@2
|
578 Sn-1;
|
rlm@2
|
579 Sn;
|
rlm@2
|
580 end;
|
rlm@2
|
581 end;
|
rlm@2
|
582 end:
|
rlm@2
|
583 end
|
rlm@2
|
584
|
rlm@2
|
585 </pre>
|
rlm@2
|
586
|
rlm@2
|
587
|
rlm@2
|
588
|
rlm@2
|
589
|
rlm@2
|
590 <p>
|
rlm@2
|
591 It is not immediately apparent that this sequencing can be expressed in a
|
rlm@2
|
592 purely applicative language. We can, however, take advantage of the implicit
|
rlm@2
|
593 sequencing of applicative order evaluation. Thus, for example, we may write a
|
rlm@2
|
594 two-statement sequence as follows:
|
rlm@2
|
595 </p>
|
rlm@2
|
596
|
rlm@2
|
597
|
rlm@2
|
598
|
rlm@2
|
599 <pre class="src src-clojure">((<span style="color: #8cd0d3;">fn</span>[dummy] S2) S1)
|
rlm@2
|
600
|
rlm@2
|
601 </pre>
|
rlm@2
|
602
|
rlm@2
|
603
|
rlm@2
|
604
|
rlm@2
|
605
|
rlm@2
|
606 <p>
|
rlm@2
|
607 where <code>dummy</code> is an identifier not used in S2. From this it is
|
rlm@2
|
608 manifest that the value of S1 is ignored, and so is useful only for
|
rlm@2
|
609 side effects. (Note that we did not claim that S1 is expressed in a
|
rlm@2
|
610 purely applicative language, but only that the sequencing can be so
|
rlm@2
|
611 expressed.) From now on we will use the form <code>(BLOCK S1 S2)</code> as an
|
rlm@2
|
612 abbreviation for this expression, and <code>(BLOCK S1 S2...Sn-1 Sn)</code> as an
|
rlm@2
|
613 abbreviation for
|
rlm@2
|
614 </p>
|
rlm@2
|
615
|
rlm@2
|
616
|
rlm@2
|
617
|
rlm@2
|
618 <pre class="src src-algol">(BLOCK S1 (BLOCK S2 (BLOCK ... (BLOCK Sn-1 Sn)...)))
|
rlm@2
|
619
|
rlm@2
|
620 </pre>
|
rlm@2
|
621
|
rlm@2
|
622
|
rlm@2
|
623
|
rlm@2
|
624
|
rlm@2
|
625 </div>
|
rlm@2
|
626
|
rlm@2
|
627 </div>
|
rlm@2
|
628
|
rlm@2
|
629 <div id="outline-container-3-2" class="outline-3">
|
rlm@2
|
630 <h3 id="sec-3-2"><span class="section-number-3">3.2</span> 2.2. The G0 TO Statement </h3>
|
rlm@2
|
631 <div class="outline-text-3" id="text-3-2">
|
rlm@2
|
632
|
rlm@2
|
633
|
rlm@2
|
634 <p>
|
rlm@2
|
635 A more general imperative structure is the compound statement with
|
rlm@2
|
636 labels and G0 T0s. Consider the following code fragment due to
|
rlm@2
|
637 Jacopini, taken from Knuth: [Knuth 74]
|
rlm@2
|
638 </p>
|
rlm@2
|
639
|
rlm@2
|
640
|
rlm@2
|
641 <pre class="src src-algol">begin
|
rlm@2
|
642 L1: if B1 then go to L2; S1;
|
rlm@2
|
643 if B2 then go to L2; S2;
|
rlm@2
|
644 go to L1;
|
rlm@2
|
645 L2: S3;
|
rlm@2
|
646
|
rlm@2
|
647 </pre>
|
rlm@2
|
648
|
rlm@2
|
649
|
rlm@2
|
650
|
rlm@2
|
651
|
rlm@2
|
652 <p>
|
rlm@2
|
653 It is perhaps surprising that this piece of code can be <i>syntactically</i>
|
rlm@2
|
654 transformed into a purely applicative style. For example, in SCHEME we
|
rlm@2
|
655 could write:
|
rlm@2
|
656 </p>
|
rlm@2
|
657
|
rlm@2
|
658
|
rlm@2
|
659
|
rlm@2
|
660 <pre class="src src-clojure">(<span style="color: #f0dfaf; font-weight: bold;">in-ns</span> 'categorical.imperative)
|
rlm@2
|
661 (<span style="color: #f0dfaf; font-weight: bold;">let</span>
|
rlm@2
|
662 [L1 (<span style="color: #8cd0d3;">fn</span>[]
|
rlm@2
|
663 (<span style="color: #f0dfaf; font-weight: bold;">if</span> B1 (L2) (<span style="color: #f0dfaf; font-weight: bold;">do</span> S1
|
rlm@2
|
664 (<span style="color: #f0dfaf; font-weight: bold;">if</span> B2 (L2) (<span style="color: #f0dfaf; font-weight: bold;">do</span> S2 (L1))))))
|
rlm@2
|
665 L2 (<span style="color: #8cd0d3;">fn</span>[] S3)]
|
rlm@2
|
666 (L1))
|
rlm@2
|
667
|
rlm@2
|
668 </pre>
|
rlm@2
|
669
|
rlm@2
|
670
|
rlm@2
|
671
|
rlm@2
|
672
|
rlm@2
|
673 <p>
|
rlm@2
|
674 As with the D0 loop, this transformation depends critically on SCHEME's
|
rlm@2
|
675 treatment of tail-recursion and on lexical scoping of variables. The labels
|
rlm@2
|
676 are names of functions of no arguments. In order to ‘go to" the labeled code,
|
rlm@2
|
677 we merely call the function named by that label.
|
rlm@2
|
678 </p>
|
rlm@2
|
679 </div>
|
rlm@2
|
680
|
rlm@2
|
681 </div>
|
rlm@2
|
682
|
rlm@2
|
683 <div id="outline-container-3-3" class="outline-3">
|
rlm@2
|
684 <h3 id="sec-3-3"><span class="section-number-3">3.3</span> 2.3. Simple Assignment </h3>
|
rlm@2
|
685 <div class="outline-text-3" id="text-3-3">
|
rlm@2
|
686
|
rlm@2
|
687 <p>Of course, all this sequencing of statements is useless unless the
|
rlm@2
|
688 statements have side effects. An important side effect is assignment. For
|
rlm@2
|
689 example, one often uses assignment to place intermediate results in a named
|
rlm@2
|
690 location (i.e. a variable) so that they may be used more than once later
|
rlm@2
|
691 without recomputing them:
|
rlm@2
|
692 </p>
|
rlm@2
|
693
|
rlm@2
|
694
|
rlm@2
|
695
|
rlm@2
|
696 <pre class="src src-algol">begin
|
rlm@2
|
697 real a2, sqrtdisc;
|
rlm@2
|
698 a2 := 2*a;
|
rlm@2
|
699 sqrtdisc := sqrt(b^2 - 4*a*c);
|
rlm@2
|
700 root1 := (- b + sqrtdisc) / a2;
|
rlm@2
|
701 root2 := (- b - sqrtdisc) / a2;
|
rlm@2
|
702 print(root1);
|
rlm@2
|
703 print(root2);
|
rlm@2
|
704 print(root1 + root2);
|
rlm@2
|
705 end
|
rlm@2
|
706
|
rlm@2
|
707 </pre>
|
rlm@2
|
708
|
rlm@2
|
709
|
rlm@2
|
710
|
rlm@2
|
711
|
rlm@2
|
712 <p>
|
rlm@2
|
713 It is well known that such naming of intermediate results may be accomplished
|
rlm@2
|
714 by calling a function and binding the formal parameter variables to the
|
rlm@2
|
715 results:
|
rlm@2
|
716 </p>
|
rlm@2
|
717
|
rlm@2
|
718
|
rlm@2
|
719
|
rlm@2
|
720 <pre class="src src-clojure">(<span style="color: #8cd0d3;">fn</span> [a2 sqrtdisc]
|
rlm@2
|
721 ((<span style="color: #8cd0d3;">fn</span>[root1 root2]
|
rlm@2
|
722 (<span style="color: #f0dfaf; font-weight: bold;">do</span> (<span style="color: #8cd0d3;">println</span> root1)
|
rlm@2
|
723 (<span style="color: #8cd0d3;">println</span> root2)
|
rlm@2
|
724 (<span style="color: #8cd0d3;">println</span> (<span style="color: #8cd0d3;">+</span> root1 root2))))
|
rlm@2
|
725 (<span style="color: #8cd0d3;">/</span> (<span style="color: #8cd0d3;">+</span> (<span style="color: #8cd0d3;">-</span> b) sqrtdisc) a2)
|
rlm@2
|
726 (<span style="color: #8cd0d3;">/</span> (<span style="color: #8cd0d3;">-</span> (<span style="color: #8cd0d3;">-</span> b) sqrtdisc) a2))
|
rlm@2
|
727
|
rlm@2
|
728 (<span style="color: #8cd0d3;">*</span> 2 a)
|
rlm@2
|
729 (sqrt (<span style="color: #8cd0d3;">-</span> (<span style="color: #8cd0d3;">*</span> b b) (<span style="color: #8cd0d3;">*</span> 4 a c))))
|
rlm@2
|
730
|
rlm@2
|
731 </pre>
|
rlm@2
|
732
|
rlm@2
|
733
|
rlm@2
|
734
|
rlm@2
|
735 <p>
|
rlm@2
|
736 This technique can be extended to handle all simple variable assignments which
|
rlm@2
|
737 appear as statements in blocks, even if arbitrary G0 T0 statements also appear
|
rlm@2
|
738 in such blocks. {Note Mccarthywins}
|
rlm@2
|
739 </p>
|
rlm@2
|
740 <p>
|
rlm@2
|
741 For example, here is a program which uses G0 TO statements in the form
|
rlm@2
|
742 presented before; it determines the parity of a non-negative integer by
|
rlm@2
|
743 counting it down until it reaches zero.
|
rlm@2
|
744 </p>
|
rlm@2
|
745
|
rlm@2
|
746
|
rlm@2
|
747
|
rlm@2
|
748 <pre class="src src-algol">begin
|
rlm@2
|
749 L1: if a = 0 then begin parity := 0; go to L2; end;
|
rlm@2
|
750 a := a - 1;
|
rlm@2
|
751 if a = 0 then begin parity := 1; go to L2; end;
|
rlm@2
|
752 a := a - 1;
|
rlm@2
|
753 go to L1;
|
rlm@2
|
754 L2: print(parity);
|
rlm@2
|
755
|
rlm@2
|
756 </pre>
|
rlm@2
|
757
|
rlm@2
|
758
|
rlm@2
|
759
|
rlm@2
|
760
|
rlm@2
|
761 <p>
|
rlm@2
|
762 This can be expressed in SCHEME:
|
rlm@2
|
763 </p>
|
rlm@2
|
764
|
rlm@2
|
765
|
rlm@2
|
766
|
rlm@2
|
767 <pre class="src src-clojure">(<span style="color: #f0dfaf; font-weight: bold;">let</span>
|
rlm@2
|
768 [L1 (<span style="color: #8cd0d3;">fn</span> [a parity]
|
rlm@2
|
769 (<span style="color: #f0dfaf; font-weight: bold;">if</span> (zero? a) (L2 a 0)
|
rlm@2
|
770 (L3 (<span style="color: #8cd0d3;">dec</span> a) parity)))
|
rlm@2
|
771 L3 (<span style="color: #8cd0d3;">fn</span> [a parity]
|
rlm@2
|
772 (<span style="color: #f0dfaf; font-weight: bold;">if</span> (zero? a) (L2 a 1)
|
rlm@2
|
773 (L1 (<span style="color: #8cd0d3;">dec</span> a) parity)))
|
rlm@2
|
774 L2 (<span style="color: #8cd0d3;">fn</span> [a parity]
|
rlm@2
|
775 (<span style="color: #8cd0d3;">println</span> parity))]
|
rlm@2
|
776 (L1 a parity))
|
rlm@2
|
777
|
rlm@2
|
778 </pre>
|
rlm@2
|
779
|
rlm@2
|
780
|
rlm@2
|
781
|
rlm@2
|
782
|
rlm@2
|
783 <p>
|
rlm@2
|
784 The trick is to pass the set of variables which may be altered as arguments to
|
rlm@2
|
785 the label functions. {Note Flowgraph} It may be necessary to introduce new
|
rlm@2
|
786 labels (such as L3) so that an assignment may be transformed into the binding
|
rlm@2
|
787 for a function call. At worst, one may need as many labels as there are
|
rlm@2
|
788 statements (not counting the eliminated assignment and GO TO statements).
|
rlm@2
|
789 </p>
|
rlm@2
|
790 </div>
|
rlm@2
|
791
|
rlm@2
|
792 </div>
|
rlm@2
|
793
|
rlm@2
|
794 <div id="outline-container-3-4" class="outline-3">
|
rlm@2
|
795 <h3 id="sec-3-4"><span class="section-number-3">3.4</span> Compound Expressions ' </h3>
|
rlm@2
|
796 <div class="outline-text-3" id="text-3-4">
|
rlm@2
|
797
|
rlm@2
|
798 <p>At this point we are almost in a position to model the most general
|
rlm@2
|
799 form of compound statement. In LISP, this is called the 'PROG feature". In
|
rlm@2
|
800 addition to statement sequencing and G0 T0 statements, one can return a <i>value</i>
|
rlm@2
|
801 from a PROG by using the RETURN statement.
|
rlm@2
|
802 </p>
|
rlm@2
|
803 <p>
|
rlm@2
|
804 Let us first consider the simplest compound statement, which in SCHEME
|
rlm@2
|
805 we call BLOCK. Recall that
|
rlm@2
|
806 <code>(BLOCK s1 sz)</code> is defined to be <code>((lambda (dummy) s2) s1)</code>
|
rlm@2
|
807 </p>
|
rlm@2
|
808 <p>
|
rlm@2
|
809 Notice that this not only performs Sl before S2, but also returns the value of
|
rlm@2
|
810 S2. Furthermore, we defined <code>(BLOCK S1 S2 ... Sn)</code> so that it returns the value
|
rlm@2
|
811 of <code>Sn</code>. Thus BLOCK may be used as a compound expression, and models a LISP
|
rlm@2
|
812 PROGN, which is a PROG with no G0 T0 statements and an implicit RETURN of the
|
rlm@2
|
813 last ``statement'' (really an expression).
|
rlm@2
|
814 </p>
|
rlm@2
|
815 <p>
|
rlm@2
|
816 Host LISP compilers compile D0 expressions by macro-expansion. We have
|
rlm@2
|
817 already seen one way to do this in SCHEME using only variable binding. A more
|
rlm@2
|
818 common technique is to expand the D0 into a PROG, using variable assignments
|
rlm@2
|
819 instead of bindings. Thus the iterative factorial program:
|
rlm@2
|
820 </p>
|
rlm@2
|
821
|
rlm@2
|
822
|
rlm@2
|
823
|
rlm@2
|
824 <pre class="src src-clojure">(oarxnz FACT .
|
rlm@2
|
825 (LAMaoA (n) .
|
rlm@2
|
826 (D0 ((M N (<span style="color: #8cd0d3;">-</span> H 1))
|
rlm@2
|
827 (Ans 1 (<span style="color: #8cd0d3;">*</span> M Ans)))
|
rlm@2
|
828 ((<span style="color: #8cd0d3;">-</span> H 0) A<span style="color: #cc9393;">"$))))</span>
|
rlm@2
|
829
|
rlm@2
|
830 </pre>
|
rlm@2
|
831
|
rlm@2
|
832
|
rlm@2
|
833
|
rlm@2
|
834
|
rlm@2
|
835 <p>
|
rlm@2
|
836 would expand into:
|
rlm@2
|
837 </p>
|
rlm@2
|
838
|
rlm@2
|
839
|
rlm@2
|
840
|
rlm@2
|
841 <pre class="src src-clojure">(DEFINE FACT
|
rlm@2
|
842 . (LAMeoA (M)
|
rlm@2
|
843 (PRO6 (M Ans)
|
rlm@2
|
844 (sszro M n
|
rlm@2
|
845 Ans 1) ~
|
rlm@2
|
846 LP (tr (<span style="color: #8cd0d3;">-</span> M 0) (RETURN Ans))
|
rlm@2
|
847 (ssero M (<span style="color: #8cd0d3;">-</span> n 1)
|
rlm@2
|
848 Ans (' M Ans))
|
rlm@2
|
849 (60 LP))))
|
rlm@2
|
850
|
rlm@2
|
851 </pre>
|
rlm@2
|
852
|
rlm@2
|
853
|
rlm@2
|
854
|
rlm@2
|
855
|
rlm@2
|
856 <p>
|
rlm@2
|
857 where SSETQ is a simultaneous multiple assignment operator. (SSETQ is not a
|
rlm@2
|
858 SCHEME (or LISP) primitive. It can be defined in terms of a single assignment
|
rlm@2
|
859 operator, but we are more interested here in RETURN than in simultaneous
|
rlm@2
|
860 assignment. The SSETQ's will all be removed anyway and modelled by lambda
|
rlm@2
|
861 binding.) We can apply the same technique we used before to eliminate G0 T0
|
rlm@2
|
862 statements and assignments from compound statements:
|
rlm@2
|
863 </p>
|
rlm@2
|
864
|
rlm@2
|
865
|
rlm@2
|
866
|
rlm@2
|
867 <pre class="src src-clojure">(DEFINE FACT
|
rlm@2
|
868 (LAHBOA (I)
|
rlm@2
|
869 (LABELS ((L1 (LAManA (M Ans)
|
rlm@2
|
870 (LP n 1)))
|
rlm@2
|
871 (LP (LAMaoA (M Ans)
|
rlm@2
|
872 (IF (<span style="color: #8cd0d3;">-</span> M o) (nztunn Ans)
|
rlm@2
|
873 (£2 H An$))))
|
rlm@2
|
874 (L2 (LAMaoA (M An )
|
rlm@2
|
875 (LP (<span style="color: #8cd0d3;">-</span> <span style="color: #cc9393;">" 1) (' H flN$)))))</span>
|
rlm@2
|
876 <span style="color: #e37170; background-color: #332323;">(</span><span style="color: #cc9393;">L1 NIL NlL))))</span>
|
rlm@2
|
877
|
rlm@2
|
878 </pre>
|
rlm@2
|
879
|
rlm@2
|
880
|
rlm@2
|
881 <p>
|
rlm@2
|
882 clojure
|
rlm@2
|
883 </p>
|
rlm@2
|
884 <p>
|
rlm@2
|
885 We still haven't done anything about RETURN. Let's see…
|
rlm@2
|
886 </p><ul>
|
rlm@2
|
887 <li>==> the value of (FACT 0) is the value of (Ll NIL NIL)
|
rlm@2
|
888 </li>
|
rlm@2
|
889 <li>==> which is the value of (LP 0 1)
|
rlm@2
|
890 </li>
|
rlm@2
|
891 <li>==> which is the value of (IF (= 0 0) (RETURN 1) (L2 0 1))
|
rlm@2
|
892 </li>
|
rlm@2
|
893 <li>==> which is the value of (RETURN 1)
|
rlm@2
|
894 </li>
|
rlm@2
|
895 </ul>
|
rlm@2
|
896
|
rlm@2
|
897
|
rlm@2
|
898 <p>
|
rlm@2
|
899 Notice that if RETURN were the <i>identity function</i> (LAMBDA (X) X), we would get the right answer. This is in fact a
|
rlm@2
|
900 general truth: if we Just replace a call to RETURN with its argument, then
|
rlm@2
|
901 our old transformation on compound statements extends to general compound
|
rlm@2
|
902 expressions, i.e. PROG.
|
rlm@2
|
903 </p>
|
rlm@2
|
904 </div>
|
rlm@2
|
905 </div>
|
rlm@2
|
906
|
rlm@2
|
907 </div>
|
rlm@2
|
908
|
rlm@2
|
909 <div id="outline-container-4" class="outline-2">
|
rlm@2
|
910 <h2 id="sec-4"><span class="section-number-2">4</span> Continuations </h2>
|
rlm@2
|
911 <div class="outline-text-2" id="text-4">
|
rlm@2
|
912
|
rlm@2
|
913 <p>Up to now we have thought of SCHEME's LAMBDA expressions as functions,
|
rlm@2
|
914 and of a combination such as <code>(G (F X Y))</code> as meaning ``apply the function F to
|
rlm@2
|
915 the values of X and Y, and return a value so that the function G can be
|
rlm@2
|
916 applied and return a value …'' But notice that we have seldom used LAMBDA
|
rlm@2
|
917 expressions as functions. Rather, we have used them as control structures and
|
rlm@2
|
918 environment modifiers. For example, consider the expression:
|
rlm@2
|
919 <code>(BLOCK (PRINT 3) (PRINT 4))</code>
|
rlm@2
|
920 </p>
|
rlm@2
|
921 <p>
|
rlm@2
|
922 This is defined to be an abbreviation for:
|
rlm@2
|
923 <code>((LAMBDA (DUMMY) (PRINT 4)) (PRINT 3))</code>
|
rlm@2
|
924 </p>
|
rlm@2
|
925 <p>
|
rlm@2
|
926 We do not care about the value of this BLOCK expression; it follows that we
|
rlm@2
|
927 do not care about the value of the <code>(LAMBDA (DUMMY) ...)</code>. We are not using
|
rlm@2
|
928 LAMBDA as a function at all.
|
rlm@2
|
929 </p>
|
rlm@2
|
930 <p>
|
rlm@2
|
931 It is possible to write useful programs in terms of LAHBDA expressions
|
rlm@2
|
932 in which we never care about the value of <i>any</i> lambda expression. We have
|
rlm@2
|
933 already demonstrated how one could represent any "FORTRAN" program in these
|
rlm@2
|
934 terms: all one needs is PROG (with G0 and SETQ), and PRINT to get the answers
|
rlm@2
|
935 out. The ultimate generalization of this imperative programing style is
|
rlm@2
|
936 <i>continuation-passing</i>. (Note Churchwins} .
|
rlm@2
|
937 </p>
|
rlm@2
|
938
|
rlm@2
|
939 </div>
|
rlm@2
|
940
|
rlm@2
|
941 <div id="outline-container-4-1" class="outline-3">
|
rlm@2
|
942 <h3 id="sec-4-1"><span class="section-number-3">4.1</span> Continuation-Passing Recursion </h3>
|
rlm@2
|
943 <div class="outline-text-3" id="text-4-1">
|
rlm@2
|
944
|
rlm@2
|
945 <p>Consider the following alternative definition of FACT. It has an extra
|
rlm@2
|
946 argument, the continuation, which is a function to call with the answer, when
|
rlm@2
|
947 we have it, rather than return a value
|
rlm@2
|
948 </p>
|
rlm@2
|
949
|
rlm@2
|
950
|
rlm@2
|
951
|
rlm@2
|
952 <pre class="src src-algol.">procedure Inc!(n, c); value n, c;
|
rlm@2
|
953 integer n: procedure c(integer value);
|
rlm@2
|
954 if n-=0 then c(l) else
|
rlm@2
|
955 begin
|
rlm@2
|
956 procedure l(!mp(d) value a: integer a;
|
rlm@2
|
957 c(mm);
|
rlm@2
|
958 Iacl(n-1, romp):
|
rlm@2
|
959 end;
|
rlm@2
|
960
|
rlm@2
|
961 </pre>
|
rlm@2
|
962
|
rlm@2
|
963
|
rlm@2
|
964
|
rlm@2
|
965
|
rlm@2
|
966
|
rlm@2
|
967 <pre class="src src-clojure">(<span style="color: #f0dfaf; font-weight: bold;">in-ns</span> 'categorical.imperative)
|
rlm@2
|
968 (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">fact-cps</span>[n k]
|
rlm@2
|
969 (<span style="color: #f0dfaf; font-weight: bold;">if</span> (zero? n) (k 1)
|
rlm@2
|
970 (<span style="color: #f0dfaf; font-weight: bold;">recur</span> (<span style="color: #8cd0d3;">dec</span> n) (<span style="color: #8cd0d3;">fn</span>[a] (k (<span style="color: #8cd0d3;">*</span> n a))))))
|
rlm@2
|
971
|
rlm@2
|
972 </pre>
|
rlm@2
|
973
|
rlm@2
|
974
|
rlm@2
|
975 <p>
|
rlm@2
|
976 clojure
|
rlm@2
|
977 It is fairly clumsy to use this version of‘ FACT in ALGOL; it is necessary to
|
rlm@2
|
978 do something like this:
|
rlm@2
|
979 </p>
|
rlm@2
|
980
|
rlm@2
|
981
|
rlm@2
|
982
|
rlm@2
|
983 <pre class="src src-algol">begin
|
rlm@2
|
984 integer ann
|
rlm@2
|
985 procedure :emp(x); value 2:; integer x;
|
rlm@2
|
986 ans :1 x;
|
rlm@2
|
987 ]'act(3. temp);
|
rlm@2
|
988 comment Now the variable <span style="color: #cc9393;">"am"</span> has 6;
|
rlm@2
|
989 end;
|
rlm@2
|
990
|
rlm@2
|
991 </pre>
|
rlm@2
|
992
|
rlm@2
|
993
|
rlm@2
|
994
|
rlm@2
|
995
|
rlm@2
|
996 <p>
|
rlm@2
|
997 Procedure <code>fact</code> does not return a value, nor does <code>temp</code>; we must use a side
|
rlm@2
|
998 effect to get the answer out.
|
rlm@2
|
999 </p>
|
rlm@2
|
1000 <p>
|
rlm@2
|
1001 <code>FACT</code> is somewhat easier to use in SCHEME. We can call it like an
|
rlm@2
|
1002 ordinary function in SCHEME if we supply an identity function as the second
|
rlm@2
|
1003 argument. For example, <code>(FACT 3 (LAMBDA (X) X))</code> returns 6. Alternatively, we
|
rlm@2
|
1004 could write <code>(FACT 3 (LAHBDA (X) (PRINT X)))</code>; we do not care about the value
|
rlm@2
|
1005 of this, but about what gets printed. A third way to use the value is to
|
rlm@2
|
1006 write
|
rlm@2
|
1007 <code>(FACT 3 (LAMBDA (x) (SQRT x)))</code>
|
rlm@2
|
1008 instead of
|
rlm@2
|
1009 <code>(SQRT (FACT 3 (LAMBDA (x) x)))</code>
|
rlm@2
|
1010 </p>
|
rlm@2
|
1011 <p>
|
rlm@2
|
1012 In either of these cases we care about the value of the continuation given to
|
rlm@2
|
1013 FACT. Thus we care about the value of FACT if and only if we care about the
|
rlm@2
|
1014 value of its continuation!
|
rlm@2
|
1015 </p>
|
rlm@2
|
1016 <p>
|
rlm@2
|
1017 We can redefine other functions to take continuations in the same way.
|
rlm@2
|
1018 For example, suppose we had arithmetic primitives which took continuations; to
|
rlm@2
|
1019 prevent confusion, call the version of "+" which takes a continuation '++",
|
rlm@2
|
1020 etc. Instead of writing
|
rlm@2
|
1021 <code>(- (+ B Z)(* 4 A C))</code>
|
rlm@2
|
1022 we can write
|
rlm@2
|
1023 </p>
|
rlm@2
|
1024
|
rlm@2
|
1025
|
rlm@2
|
1026 <pre class="src src-clojure">(<span style="color: #f0dfaf; font-weight: bold;">in-ns</span> 'categorical.imperative)
|
rlm@2
|
1027 (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">enable-continuation</span> <span style="color: #8fb28f;">"Makes f take a continuation as an additional argument."</span>[f]
|
rlm@2
|
1028 (<span style="color: #8cd0d3;">fn</span>[& args] ((<span style="color: #8cd0d3;">fn</span>[k] (k (<span style="color: #8cd0d3;">apply</span> f (<span style="color: #8cd0d3;">reverse</span> (<span style="color: #8cd0d3;">rest</span> (<span style="color: #8cd0d3;">reverse</span> args)))))) (<span style="color: #8cd0d3;">last</span> args)) ))
|
rlm@2
|
1029 (<span style="color: #f0dfaf; font-weight: bold;">def</span> <span style="color: #f0dfaf;">+&</span> (enable-continuation +))
|
rlm@2
|
1030 (<span style="color: #f0dfaf; font-weight: bold;">def</span> <span style="color: #f0dfaf;">*&</span> (enable-continuation *))
|
rlm@2
|
1031 (<span style="color: #f0dfaf; font-weight: bold;">def</span> <span style="color: #f0dfaf;">-&</span> (enable-continuation -))
|
rlm@2
|
1032
|
rlm@2
|
1033
|
rlm@2
|
1034 (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">quadratic</span>[a b c k]
|
rlm@2
|
1035 (*& b b
|
rlm@2
|
1036 (<span style="color: #8cd0d3;">fn</span>[x] (*& 4 a c
|
rlm@2
|
1037 (<span style="color: #8cd0d3;">fn</span>[y]
|
rlm@2
|
1038 (-& x y k))))))
|
rlm@2
|
1039
|
rlm@2
|
1040 </pre>
|
rlm@2
|
1041
|
rlm@2
|
1042
|
rlm@2
|
1043
|
rlm@2
|
1044
|
rlm@2
|
1045 <p>
|
rlm@2
|
1046 where <code>k</code> is the continuation for the entire expression.
|
rlm@2
|
1047 </p>
|
rlm@2
|
1048 <p>
|
rlm@2
|
1049 This is an obscure way to write an algebraic expression, and we would
|
rlm@2
|
1050 not advise writing code this way in general, but continuation-passing brings
|
rlm@2
|
1051 out certain important features of the computation:
|
rlm@2
|
1052 </p><ul>
|
rlm@2
|
1053 <li><sup><a class="footref" name="fnr.1" href="#fn.1">1</a></sup> The operations to be performed appear in the order in which they are
|
rlm@2
|
1054 </li>
|
rlm@2
|
1055 </ul>
|
rlm@2
|
1056
|
rlm@2
|
1057 <p>performed. In fact, they <i>must</i> be performed in this
|
rlm@2
|
1058 order. Continuation- passing removes the need for the rule about
|
rlm@2
|
1059 left-to-right argument evaluation{Note Evalorder)
|
rlm@2
|
1060 </p><ul>
|
rlm@2
|
1061 <li><sup><a class="footref" name="fnr.2" href="#fn.2">2</a></sup> In the usual applicative expression there are two implicit
|
rlm@2
|
1062 temporary values: those of <code>(* B B)</code> and <code>(* 4 A C)</code>. The first of
|
rlm@2
|
1063 these values must be preserved over the computation of the second,
|
rlm@2
|
1064 whereas the second is used as soon as it is produced. These facts
|
rlm@2
|
1065 are <i>manifest</i> in the appearance and use of the variable X and Y in
|
rlm@2
|
1066 the continuation-passing version.
|
rlm@2
|
1067 </li>
|
rlm@2
|
1068 </ul>
|
rlm@2
|
1069
|
rlm@2
|
1070
|
rlm@2
|
1071 <p>
|
rlm@2
|
1072 In short, the continuation-passing version specifies <i>exactly</i> and
|
rlm@2
|
1073 explicitly what steps are necessary to compute the value of the
|
rlm@2
|
1074 expression. One can think of conventional functional application
|
rlm@2
|
1075 for value as being an abbreviation for the more explicit
|
rlm@2
|
1076 continuation-passing style. Alternatively, one can think of the
|
rlm@2
|
1077 interpreter as supplying to each function an implicit default
|
rlm@2
|
1078 continuation of one argument. This continuation will receive the
|
rlm@2
|
1079 value of the function as its argument, and then carry on the
|
rlm@2
|
1080 computation. In an interpreter this implicit continuation is
|
rlm@2
|
1081 represented by the control stack mechanism for function returns.
|
rlm@2
|
1082 Now consider what computational steps are implied by:
|
rlm@2
|
1083 </p>
|
rlm@2
|
1084 <p>
|
rlm@2
|
1085 <code>(LAMBDA (A B C ...) (F X Y Z ...))</code> when we "apply" the LAMBDA
|
rlm@2
|
1086 expression we have some values to apply it to; we let the names A,
|
rlm@2
|
1087 B, C … refer to these values. We then determine the values of X,
|
rlm@2
|
1088 Y, Z … and pass these values (along with "the buck",
|
rlm@2
|
1089 i.e. control!) to the lambda expression F (F is either a lambda
|
rlm@2
|
1090 expression or a name for one). Passing control to F is an
|
rlm@2
|
1091 unconditional transfer. (Note Jrsthack) {Note Hewitthack) Note that
|
rlm@2
|
1092 we want values from X, Y, Z, … If these are simple expressions,
|
rlm@2
|
1093 such as variables, constants, or LAMBDA expressions, the evaluation
|
rlm@2
|
1094 process is trivial, in that no temporary storage is required. In
|
rlm@2
|
1095 pure continuation-passing style, all evaluations are trivial: no
|
rlm@2
|
1096 combination is nested within another, and therefore no ‘hidden
|
rlm@2
|
1097 temporaries" are required. But if X is a combination, say (G P Q),
|
rlm@2
|
1098 then we want to think of G as a function, because we want a value
|
rlm@2
|
1099 from it, and we will need an implicit temporary place to keep the
|
rlm@2
|
1100 result while evaluating Y and Z. (An interpreter usually keeps these
|
rlm@2
|
1101 temporary places in the control stack!) On the other hand, we do not
|
rlm@2
|
1102 necessarily need a value from F. This is what we mean by tail-
|
rlm@2
|
1103 recursion: F is called tail-recursively, whereas G is not. A better
|
rlm@2
|
1104 name for tail-recursion would be "tail-transfer", since no real
|
rlm@2
|
1105 recursion is implied. This is why we have made such a fuss about
|
rlm@2
|
1106 tail-recursion: it can be used for transfer of control without
|
rlm@2
|
1107 making any commitment about whether the expression expected to
|
rlm@2
|
1108 return a value. Thus it can be used to model statement-like control
|
rlm@2
|
1109 structures. Put another way, tail—recursion does not require a
|
rlm@2
|
1110 control stack as nested recursion does. In our models of iteration
|
rlm@2
|
1111 and imperative style all the LAMBDA expressions used for control (to
|
rlm@2
|
1112 simulate GO statements, for example) are called in tail-recursive
|
rlm@2
|
1113 fashion.
|
rlm@2
|
1114 </p>
|
rlm@2
|
1115 </div>
|
rlm@2
|
1116
|
rlm@2
|
1117 </div>
|
rlm@2
|
1118
|
rlm@2
|
1119 <div id="outline-container-4-2" class="outline-3">
|
rlm@2
|
1120 <h3 id="sec-4-2"><span class="section-number-3">4.2</span> Escape Expressions </h3>
|
rlm@2
|
1121 <div class="outline-text-3" id="text-4-2">
|
rlm@2
|
1122
|
rlm@2
|
1123 <p>Reynolds [Reynolds 72] defines the construction
|
rlm@2
|
1124 = escape x in r =
|
rlm@2
|
1125 </p>
|
rlm@2
|
1126 <p>
|
rlm@2
|
1127 to evaluate the expression \(r\) in an environment such that the variable \(x\) is
|
rlm@2
|
1128 bound to an escape function. If the escape function is never applied, then
|
rlm@2
|
1129 the value of the escape expression is the value of \(r\). If the escape function
|
rlm@2
|
1130 is applied to an argument \(a\), however, then evaluation of \(r\) is aborted and the
|
rlm@2
|
1131 escape expression returns \(a\). {Note J-operator} (Reynolds points out that
|
rlm@2
|
1132 this definition is not quite accurate, since the escape function may be called
|
rlm@2
|
1133 even after the escape expression has returned a value; if this happens, it
|
rlm@2
|
1134 “returns again"!)
|
rlm@2
|
1135 </p>
|
rlm@2
|
1136 <p>
|
rlm@2
|
1137 As an example of the use of an escape expression, consider this
|
rlm@2
|
1138 procedure to compute the harmonic mean of an array of numbers. If any of the
|
rlm@2
|
1139 numbers is zero, we want the answer to be zero. We have a function hannaunl
|
rlm@2
|
1140 which will sum the reciprocals of numbers in an array, or call an escape
|
rlm@2
|
1141 function with zero if any of the numbers is zero. (The implementation shown
|
rlm@2
|
1142 here is awkward because ALGOL requires that a function return its value by
|
rlm@2
|
1143 assignment.)
|
rlm@2
|
1144 </p>
|
rlm@2
|
1145
|
rlm@2
|
1146
|
rlm@2
|
1147 <pre class="src src-algol">begin
|
rlm@2
|
1148 real procedure Imrmsum(a, n. escfun)§ p
|
rlm@2
|
1149 real array at integer n; real procedure esciun(real);
|
rlm@2
|
1150 begin
|
rlm@2
|
1151 real sum;
|
rlm@2
|
1152 sum := 0;
|
rlm@2
|
1153 for i :1 0 until n-l do
|
rlm@2
|
1154 begin
|
rlm@2
|
1155 if a[i]=0 then cscfun(0);
|
rlm@2
|
1156 sum :1 sum ¢ I/a[i];
|
rlm@2
|
1157 enm
|
rlm@2
|
1158 harmsum SI sum;
|
rlm@2
|
1159 end: .
|
rlm@2
|
1160 real array b[0:99]:
|
rlm@2
|
1161 print(escape x in I00/hm-m.mm(b, 100, x));
|
rlm@2
|
1162 end
|
rlm@2
|
1163
|
rlm@2
|
1164 </pre>
|
rlm@2
|
1165
|
rlm@2
|
1166
|
rlm@2
|
1167
|
rlm@2
|
1168
|
rlm@2
|
1169 <p>
|
rlm@2
|
1170 If harmsum exits normally, the number of elements is divided by the sum and
|
rlm@2
|
1171 printed. Otherwise, zero is returned from the escape expression and printed
|
rlm@2
|
1172 without the division ever occurring.
|
rlm@2
|
1173 This program can be written in SCHEME using the built-in escape
|
rlm@2
|
1174 operator <code>CATCH</code>:
|
rlm@2
|
1175 </p>
|
rlm@2
|
1176
|
rlm@2
|
1177
|
rlm@2
|
1178
|
rlm@2
|
1179 <pre class="src src-clojure">abc
|
rlm@2
|
1180
|
rlm@2
|
1181 </pre>
|
rlm@2
|
1182
|
rlm@2
|
1183
|
rlm@2
|
1184
|
rlm@2
|
1185 <div id="footnotes">
|
rlm@2
|
1186 <h2 class="footnotes">Footnotes: </h2>
|
rlm@2
|
1187 <div id="text-footnotes">
|
rlm@2
|
1188 <p class="footnote"><sup><a class="footnum" name="fn.1" href="#fnr.1">1</a></sup> DEFINITION NOT FOUND: 1
|
rlm@2
|
1189 </p>
|
rlm@2
|
1190
|
rlm@2
|
1191 <p class="footnote"><sup><a class="footnum" name="fn.2" href="#fnr.2">2</a></sup> DEFINITION NOT FOUND: 2
|
rlm@2
|
1192 </p>
|
rlm@2
|
1193 </div>
|
rlm@2
|
1194 </div>
|
rlm@2
|
1195 </div>
|
rlm@2
|
1196
|
rlm@2
|
1197 </div>
|
rlm@2
|
1198 </div>
|
rlm@2
|
1199 <div id="postamble">
|
rlm@2
|
1200 <p class="date">Date: 2011-07-15 02:49:04 EDT</p>
|
rlm@2
|
1201 <p class="author">Author: Guy Lewis Steele Jr. and Gerald Jay Sussman</p>
|
rlm@2
|
1202 <p class="creator">Org version 7.6 with Emacs version 23</p>
|
rlm@2
|
1203 <a href="http://validator.w3.org/check?uri=referer">Validate XHTML 1.0</a>
|
rlm@2
|
1204 </div>
|
rlm@2
|
1205 </div>
|
rlm@2
|
1206 </body>
|
rlm@2
|
1207 </html>
|