0 | |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/2002/REC-xhtml1-20020801/DTD/xhtml1-strict.dtd">
|
1 | |
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
|
2 | |
<head>
|
3 | |
<title>The Pixley Programming Language</title>
|
4 | |
<!-- begin html doc dynamic markup -->
|
5 | |
<script type="text/javascript" src="/contrib/jquery-1.6.4.min.js"></script>
|
6 | |
<script type="text/javascript" src="/scripts/documentation.js"></script>
|
7 | |
<!-- end html doc dynamic markup -->
|
8 | |
</head>
|
9 | |
<body>
|
10 | |
|
11 | |
<h1>The Pixley Programming Language</h1>
|
12 | |
|
13 | |
<p>Language version 2.0, distribution revision 2011.1209</p>
|
14 | |
|
15 | |
<h2>Introduction</h2>
|
16 | |
|
17 | |
<p><dfn>Pixley</dfn> is a strict and purely functional subset of R<sup>5</sup>RS Scheme.
|
18 | |
All Pixley programs are also therefore Scheme programs.</p>
|
19 | |
|
20 | |
<p>Pixley was designed for "bootstrappability". I aimed to encompass a
|
21 | |
minimal subset of Scheme that was still expressive enough to
|
22 | |
permit writing a Pixley interpreter without too much pain.</p>
|
23 | |
|
24 | |
<h2>Semantics</h2>
|
25 | |
|
26 | |
<p>Pixley implements the following functions and forms from Scheme
|
27 | |
(listed in alphabetical order):</p>
|
28 | |
|
29 | |
<ul>
|
30 | |
<li><code>car</code></li>
|
31 | |
<li><code>cdr</code></li>
|
32 | |
<li><code>cond</code> / <code>else</code></li>
|
33 | |
<li><code>cons</code></li>
|
34 | |
<li><code>equal?</code></li>
|
35 | |
<li><code>lambda</code></li>
|
36 | |
<li><code>let*</code></li>
|
37 | |
<li><code>list?</code></li>
|
38 | |
<li><code>quote</code></li>
|
39 | |
</ul>
|
40 | |
|
41 | |
<p>For the precise meanings of each of these forms,
|
42 | |
please refer to the Revised<sup>5</sup> Report on the Algorithmic Language Scheme.</p>
|
43 | |
|
44 | |
<p>Pixley only understands the Scheme datatypes of lists, symbols, function values (lambdas),
|
45 | |
and booleans. Pixley's behaviour regarding any attempt to produce a value of any other type is undefined.
|
46 | |
Neither is its behaviour defined for s-expressions which result in errors
|
47 | |
when evaluated as Scheme programs.</p>
|
48 | |
|
49 | |
<h2>Syntax</h2>
|
50 | |
|
51 | |
<p>Pixley's syntax is a strict subset of Scheme's. The meanings of
|
52 | |
syntactical constructs which are valid in Scheme but not defined in Pixley (such as
|
53 | |
numbers, strings, comments, quasiquoting, or hygienic macros) are undefined.</p>
|
54 | |
|
55 | |
<p>Of literal values, only those of list type can be directly introduced through syntactical
|
56 | |
elements. Like Scheme, a literal null list can be denoted by <code>(quote ())</code>.
|
57 | |
(However, <code>()</code> by itself is considered to be an illegal, empty application.)
|
58 | |
Literal symbols may be introduced through the <code>quote</code> form,
|
59 | |
literal function values can be produced through the <code>lambda</code>
|
60 | |
form, and the two boolean values can be produced through the use of trivial
|
61 | |
tests such as <code>(equal? (quote ()) (quote ()))</code>
|
62 | |
and <code>(equal? (quote a) (quote b))</code>.</p>
|
63 | |
|
64 | |
<h2>Reference Implementation</h2>
|
65 | |
|
66 | |
<p>The reference implementation of Pixley, <code>pixley.pix</code>,
|
67 | |
is written in 122 lines of Pixley (or, if you prefer, 122 lines of Scheme;
|
68 | |
and if you prefer more Scheme-ly metrics, it consists of 405 instances of
|
69 | |
53 unique symbols in 668 cons cells.)</p>
|
70 | |
|
71 | |
<p><code>pixley.pix</code> does not include a lexical processor:
|
72 | |
the Pixley program to be interpreted
|
73 | |
must be made available to the interpreter as a native s-expression.
|
74 | |
Since Pixley does not implement <code>define</code>, this is
|
75 | |
usually achieved by applying a textual copy of <code>pixley.pix</code>
|
76 | |
(a <code>lambda</code> expression)
|
77 | |
to the s-expression to be interpreted as a Pixley program.</p>
|
78 | |
|
79 | |
<p>Because <code>pixley.pix</code> is written in Pixley, multiple
|
80 | |
copies can be applied successively with equivalent semantics.
|
81 | |
For example, having <code>pixley.pix</code> interpret some
|
82 | |
program <code>foo.pix</code> should produce the same
|
83 | |
observable behaviour (modulo performance) as having
|
84 | |
<code>pixley.pix</code> interpret <code>pixley.pix</code> interpreting
|
85 | |
<code>foo.pix</code>, or having
|
86 | |
<code>pixley.pix</code> interpret <code>pixley.pix</code>
|
87 | |
interpret <code>pixley.pix</code> interpreting
|
88 | |
<code>foo.pix</code>, etc. etc. ad infinitum.
|
89 | |
The Scheme test suite for the Pixley reference interpreter does just that,
|
90 | |
running through the set of tests at successively higher "degrees".
|
91 | |
This is an example of a <dfn>computational automorphism</dfn>
|
92 | |
and is a property of any bootstrapped universal computer (or rather,
|
93 | |
of the Turing-complete language of that computer.)</p>
|
94 | |
|
95 | |
<p>The Pixley reference interpreter is highly meta-circular,
|
96 | |
implementing e.g. Pixley's <code>car</code> simply in terms of the
|
97 | |
underlying Pixley (or Scheme) <code>car</code>. The datatypes of
|
98 | |
Pixley are likewise directly represented by the corresponding datatypes
|
99 | |
in the underlying language.
|
100 | |
Environments are represented as lists similar to association lists,
|
101 | |
except containing two-element sublists instead of pairs, because Pixley
|
102 | |
can't directly represent pairs. Each sublist's first element is a symbol
|
103 | |
naming the identifier, and the second is the value to which it is bound.</p>
|
104 | |
|
105 | |
<h2>History</h2>
|
106 | |
|
107 | |
<h3>Pixley 1.0</h3>
|
108 | |
|
109 | |
<p>Pixley 1.0 was released on May 1<sup>st</sup>, 2009, from Cupertino,
|
110 | |
California.</p>
|
111 | |
|
112 | |
<p>In addition to the 10 Scheme symbols listed above, Pixley 1.0 (and 1.1) also implemented
|
113 | |
the Scheme functions <code>cadr</code> and <code>null?</code>. However, it was
|
114 | |
found that the interpreter was actually shorter if those functions were defined
|
115 | |
only locally within the interpreter. They were thus removed from the Pixley
|
116 | |
language in version 2.0. It is easy enough to apply the same technique to any
|
117 | |
Pixley 1.0 (or 1.1) program to convert it to Pixley 2.0; simply wrap it in the following:</p>
|
118 | |
|
119 | |
<pre>
|
120 | |
(let* ((cadr (lambda (alist)
|
121 | |
(car (cdr alist))))
|
122 | |
(null? (lambda (expr)
|
123 | |
(equal? expr (quote ())))))
|
124 | |
...)
|
125 | |
</pre>
|
126 | |
|
127 | |
<h3>Pixley v1.1</h3>
|
128 | |
|
129 | |
<p>Pixley 1.1 was released on November 5<sup>th</sup>, 2010, from Evanston,
|
130 | |
Illinois.</p>
|
131 | |
|
132 | |
<p>Funny story! So I was writing writing stuff in C to compile with DICE C for AmigaOS 1.3, right?
|
133 | |
And I was looking for something to write, and I decided to implement Pixley in C.
|
134 | |
And that was going pretty well; as I was implementing each command, I was making up
|
135 | |
ad-hoc test cases for it, and I was thinking "Hey, I should record these somewhere and make a test
|
136 | |
suite for the Pixley reference distribution!" Of course, I never did record those cases, but
|
137 | |
in the following weeks I started doing various other things with the Pixley project, and
|
138 | |
at one point, decided anew that it would be a good idea to bulk up the test cases.</p>
|
139 | |
|
140 | |
<p>So I started writing more test cases, right? And I got to testing <code>list?</code>.
|
141 | |
Well, <code>(list? (lambda (x) x))</code> should be <em>false</em>, right? Sure.
|
142 | |
Except it wasn't.</p>
|
143 | |
|
144 | |
<p>Well, I went to the docs and saw that there was an easy explanation for this. This was
|
145 | |
for Pixley 1.0, mind you, and they've changed since then, but they told me that:</p>
|
146 | |
|
147 | |
<blockquote>
|
148 | |
<p>Some places where the underlying and interpreted representations must
|
149 | |
differ are in the data types, namely lists and lambda functions.</p>
|
150 | |
|
151 | |
<p>Each interpreted list is represented as a two-element underlying list. The
|
152 | |
first element is the atom <code>__list__</code> and the second
|
153 | |
element is the (interpreted) list itself.</p>
|
154 | |
|
155 | |
<p>Each interpreted lambda function is represented by an underlying list
|
156 | |
of four elements: the atom <code>__lambda__</code>,
|
157 | |
a representation of the enclosing environment, a list of the formal
|
158 | |
arguments of the function, and the (interpreted) body of the function.</p>
|
159 | |
</blockquote>
|
160 | |
|
161 | |
<p>In other words, in the
|
162 | |
reference interpreter, both lists and function values are represented with lists; you tell
|
163 | |
them apart by looking at the first element, which is <code>__lambda__</code> for a
|
164 | |
function value and <code>__list__</code> for a list. And <code>list?</code> was
|
165 | |
probably just looking at the representation list and not checking the first element,
|
166 | |
right? Sure. Except, no, it was much more.</p>
|
167 | |
|
168 | |
<p>It turns out that while function values were in fact represented by lists
|
169 | |
with <code>__lambda__</code> as the first element, lists were just represented by lists.
|
170 | |
Which means that there was an overlap between the types: a function value was, at the Pixley
|
171 | |
level, a kind of list, and could be treated just like one, for example with <code>car</code>
|
172 | |
and <code>cdr</code>. This is clearly not kosher R<sup>5</sup>RS, which has a whole
|
173 | |
<em>section</em> titled "Disjointness of types". (Of course, neither "list" nor
|
174 | |
"function value" is mentioned in that section, but I'd say the spirit of the law is pretty
|
175 | |
clear there or whatever.)</p>
|
176 | |
|
177 | |
<p>So this meant I had to fix the Pixley interpreter! But first, I had to make a decision: how to
|
178 | |
represent lists? Well, there were two general paths here: more meta-circular, or less.
|
179 | |
I could make the implementation conform to the documentation, making it less meta-circular,
|
180 | |
but then I'd have to be changing everything that built (or touched) a list to build (or check
|
181 | |
for) a list with <code>__list__</code> at its head. Doable, but kind of distasteful.
|
182 | |
Alternatively, I could make it more meta-circular: keep lists represented as lists, and
|
183 | |
go one further by representing function values as function values. This is a little unilluminating,
|
184 | |
as it no longer lays bare how function values work; but this is made up for by the fact
|
185 | |
that most of the mechanics have to continue to exist in the implementation (just in
|
186 | |
different places) and there is a modest savings of space (because we can fall back on
|
187 | |
the implementing language's semantics for cases like trying to execute a non-function.)
|
188 | |
So that's what I did.</p>
|
189 | |
|
190 | |
<p>Now, this technically changed the semantics of the language, because gosh you
|
191 | |
<em>could</em> have been relying on the fact that <code>(car (lambda (x) x))</code>
|
192 | |
evaluates to <code>__lambda__</code>, in your Pixley programs, and we can't have that,
|
193 | |
can we? So the language version was bumped up to 1.1.</p>
|
194 | |
|
195 | |
<h4>Goodies</h4>
|
196 | |
|
197 | |
<p>The Pixley 1.1 distribution also included the following supplementary material.</p>
|
198 | |
|
199 | |
<ul>
|
200 | |
<li>An enlarged test suite (previously mentioned).</li>
|
201 | |
<li>A REPL (read-eval-print loop, or "interactive mode" interpreter), written in Scheme.</li>
|
202 | |
<li>A statistics generator, written in Scheme, which counts the cons cells, symbol
|
203 | |
instances, and unique symbols present in a given s-expression. This was to measure the
|
204 | |
complexity of the Pixley interpreter.</li>
|
205 | |
<li>A Mini-Scheme driver. During my adventures in getting programs
|
206 | |
to run under AmigaOS 1.3, I compiled Mini-Scheme thereunder, and got Pixley to run
|
207 | |
under it by including the Pixley interpreter in Mini-Scheme's <code>init.scm</code> file and
|
208 | |
<code>eval</code>'ing it therein. From this I conclude that, although I have not confirmed
|
209 | |
this is in a solid way by looking at the spec or anything, Pixley is also a strict subset of
|
210 | |
R<sup>4</sup>RS Scheme.</li>
|
211 | |
</ul>
|
212 | |
|
213 | |
<h3>Pixley 2.0</h3>
|
214 | |
|
215 | |
<p>A previously mentioned, Pixley 2.0 removes the <code>cadr</code> and <code>null?</code>
|
216 | |
functions from the language.</p>
|
217 | |
|
218 | |
<h4>Goodies</h4>
|
219 | |
|
220 | |
<p>The Pixley 2.0 distribution also includes the following supplementary material.</p>
|
221 | |
|
222 | |
<ul>
|
223 | |
<li>Bourne Shell scripts to run Pixley programs which are stored in individual files.
|
224 | |
<code>pixley.sh</code> runs either a self-contained Pixley program from a single file,
|
225 | |
or evaluates a Pixley file to a function value and applies it to an S-expression stored in a
|
226 | |
second file. <code>scheme.sh</code> does the same thing, but with Scheme, as a
|
227 | |
sanity-check. By default these scripts use <code>plt-r5rs</code> for the Scheme interpreter,
|
228 | |
but that can be changed with an environment variable.</li>
|
229 | |
<li>A P-Normalizer written in Pixley, probably the first non-trivial Pixley program
|
230 | |
to be written, aside from the Pixley interpreter itself. P-Normal Pixley is a simplified version of
|
231 | |
Pixley where <code>let*</code> and <code>cond</code> only handle a single instance
|
232 | |
of what they do (like <code>let</code> and <code>if</code> in Scheme.) This form is
|
233 | |
described more fully in the <a href="../eg/p-normal.falderal">Falderal literate test
|
234 | |
suite for the P-Normalizer</a>.</li>
|
235 | |
<li>Test suites, written in Falderal, for both Pixley and the P-Normalizer. The
|
236 | |
original test suite written in Scheme, which runs successively deeper nested copies of
|
237 | |
the Pixley interpreter, is still included in the distribution.</li>
|
238 | |
<li>A few other standalone Pixley examples, including <code>reverse.pix</code>,
|
239 | |
which reverses the given list.</li>
|
240 | |
</ul>
|
241 | |
|
242 | |
<h2>Conclusion</h2>
|
243 | |
|
244 | |
<p>The last main division of a discourse,
|
245 | |
usually containing a summing up of the points
|
246 | |
and a statement of opinion or decisions reached.</p>
|
247 | |
|
248 | |
<p>Keep Smiling! (I could never stand those "Home Sweet Home" folks.)
|
249 | |
<br/>Chris Pressey
|
250 | |
<br/>December 9<sup>th</sup>, 2011
|
251 | |
<br/>Evanston, Illinois</p>
|
252 | |
|
253 | |
</body>
|
254 | |
</html>
|