1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3<head>
4<title>Introdution to Poly</title>
5<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
6</head>
7
8<body><strong>Note to online version</strong><br>
9This document was originally published as a Cambridge University Technical Report 
10(TR29) and as part of my PhD thesis, Programming Language Design with Polymorphism, 
11Cambridge University Technical Report TR49. It describes an early version of the 
12Poly language. David C. J. Matthews, August 2003. 
13<h1 align="center">INTRODUCTION TO POLY</h1>
14<h2 align="center">D.C.J. Matthews,May 1982<br>
15  Computer Laboratory,<br>
16  University of Cambridge </h2>
17
18<p><strong>Abstract</strong><br>
19  This report is a tutorial introduction to the programming language <strong>Poly</strong>. 
20  It describes how to write and run programs in Poly using the VAX/UNIX implementation. 
21  Examples given include polymorphic list functions, a double precision integer 
22  package and a subrange type constructor.</p>
23<h2>Introduction to Poly</h2>
24<p>Poly is a programming language which supports polymorphic operations. This 
25  document explains how it is used on the VAX. </p>
26<h4>1. Commands and Declarations</h4>
27<p>The system is entered by running the appropriate program (e.g.<strong> /mnt/dcjm/poly</strong> 
28  at Cambridge). The compiler will then reply with a prompt (<font face="Courier New, Courier, mono">></font>). 
29  To exit from Poly at any time type ctrl-D (end-of-text) or ctrl-C (interrupt). 
30  There are three types of instructions which can be typed to Poly; declarations 
31  of identifiers, statements (commands), or expressions. An example of a command 
32  and the output it produces is</p>
33<pre>> print("Hello");
34Hello</pre>
35<p>Note the closing semicolon which must be present to indicate the end of the 
36  command. If you forget it the compiler will print a <font face="Courier New, Courier, mono">#</font> 
37  as a prompt to indicate that the command is not yet complete.</p>
38<p>An example of an expression is</p>
39<pre>> "Hi";
40Hi </pre>
41<p>Poly prints the value of an expression without the need to type the word 'print'. 
42</p>
43<p>Commands can be grouped by enclosing them with the bracketing symbols <strong>begin</strong> 
44  and <strong>end</strong> or <strong>(</strong> and <strong>)</strong>. For instance 
45<pre>> begin
46# print("Hello");
47# print(" again")
48# end;
49Hello again</pre>
50Any object in Poly can be bound to an identifier by writing a declaration. For 
51instance 
52<pre>> let message == "Hello "; </pre>
53declares an identifier 'message' to have the value of the string 'Hello '. It 
54can be printed in the same way as the string constant. 
55<pre>> message;
56Hello </pre>
57<p>Names can be either a sequence of letters and digits starting with a letter, 
58  or a sequence of the special characters + - * = < > etc. Certain names are reserved 
59  to have special meanings and cannot be used in declarations. Those words can 
60  be written in upper, lower or mixed case, all other words are considered to 
61  be different if written in different cases. When declaring a name made up of 
62  the special characters remember to put a space between the name and the == or 
63  colon which follows it. Comments are enclosed in curly brackets <strong>{</strong> 
64  and <strong>}</strong>. They are ignored by the compiler and are equivalent 
65  to a single space or newline between words.</p>
66<h3> 2. Procedures</h3>
67<p>Statements or groups of statements can be declared by making them into procedures. 
68</p>
69<pre>> let printmessage == 
70#     proc()
71#       (print("A message ")); </pre>
72<p>A procedure consists of a procedure header (in this case the word <strong>proc</strong> 
73  and parentheses <strong>(</strong> and <strong>)</strong> ) and a body. The 
74  procedure body must be enclosed in bracketing symbols (in this case '(' and 
75  ')') even if there is only one statement. </p>
76<p> This is simply another example of a declaration. Just as previously 'message' 
77  was declared to have the value "Hello#", 'printmessage' has been declared with 
78  the value of the procedure. </p>
79<p> The procedure is called by typing the procedure name followed by <strong>()</strong>. 
80</p>
81<pre>> printmessage();
82A message </pre>
83 
84<p>The effect of this is execute the body of the procedure and so print the string. 
85</p>
86<p>Procedures can take arguments so that values can be passed to them when they 
87  are called. </p>
88<pre>> let pmessage == 
89# proc(m : string) 
90# begin 
91# print("The message is :");
92# print(m) 
93# end; </pre>
94This can be called by typing 
95<pre>> pmessage("Hello");
96The message is :Hello </pre>
97or by typing 
98<pre>> pmessage("Goodbye"); 
99The message is :Goodbye </pre>
100<h3>3. Specifications</h3>
101<p>As well as having a value all objects in Poly have a specification, analogous 
102  to a type in other languages. It is used by the compiler to ensure that only 
103  meaningful statements will be accepted. You can find the specification of a 
104  declared name x by typing <strong>? "x";</strong>. </p>
105<pre>> ? "message";
106message : string </pre>
107This means that message is a constant belonging to the type 'string'. 
108<pre>> ? "pmessage"; 
109pmessage : PROC(string) </pre>
110This means that pmessage is a procedure taking a value of type string as its argument. 
111Since message has that specification the call 
112<pre>> pmessage(message);
113The message is :Hello </pre>
114will work. Likewise the call 
115<pre>> pmessage("Hi");
116The message is :Hi </pre>
117will work because "Hi" also belongs to type string. However 
118<pre>> pmessage(pmessage); 
119Error - specifications have different forms </pre>
120 
121<p>will fail because 'pmessage' has the wrong specification. Incidentally, the 
122  specification of the procedure is the same as the header used when it was declared, 
123  ignoring the differences in the case of some of the words.</p>
124<h3>4. Integer and Boolean</h3>
125<p>So far the only constants used have been those belonging to the type string. 
126  Another type, <strong>integer</strong> provides operations on integral numbers. 
127</p>
128<pre>> print(42); 
12942 </pre>
130The usual arithmetic operations +, -, *, div, mod, succ and pred are available. 
131<pre>> 42+10-2; 50 </pre>
132However, unlike other languages all infix operators have the same precedence so 
133<pre>> 4+3*2; 14 </pre>
134 
135<p>prints 14 rather than 10. Also - is an infix operator only, there is a procedure 
136  neg which complements its argument. </p>
137<p>Another 'standard' type is <strong>boolean</strong> which has only two values 
138  <strong>true</strong> and <strong>false</strong>. Its main use is in tests for 
139  equality (the <strong>=</strong> operator), inequality (<strong><></strong>) 
140  and magnitude (<strong>> < >= <=</strong>). </p>
141<pre>> let two == 2;
142> 1 = two;
143false
144> 2 = two;
145true
146> 3 <> 4;
147true 
148> 4 >= 5;
149false </pre>
150The expression '1 = two' has type boolean. Identifiers can be declared to have 
151boolean values in the same way as integers and strings. 
152<pre>> let testtwo == two > 1; </pre>
153<p>declares testtwo to be 'true' since 'two' is greater than 1. There are three 
154  operators which work on boolean values, <strong>&</strong>, <strong>|</strong> 
155  and <strong>~</strong>. <strong>~</strong> is a prefix operator which complements 
156  its argument (i.e. if its argument was false the result is true, and vice-versa). 
157  <strong>&</strong> is an infix operator which returns true only if both its 
158  arguments are true. <strong>|</strong> is also an infix operator which returns 
159  true if either of its arguments is true. </p>
160<h3>5. If-Statement</h3>
161<p>Boolean values are particularly useful since they can be tested using <strong>if</strong>. 
162  The if-statement causes different statements to be obeyed depending on a condition. 
163</p>
164<pre>> if two = 2 
165# then print("It is two")
166# else print("It isn't two");
167It is two </pre>
168tests the value of the expression 'two = 2' and executes the statement after the 
169word <strong>then</strong> if it is true, and the statement after the word <strong>else</strong> 
170if it is false. This could be written as a procedure, 
171<pre>> let iszero == 
172# proc(i: integer) 
173# (if i = 0 then print("It is zero") 
174# else print("It isn't zero")); </pre>
175which could then be called to test a value. 
176<pre>> iszero(4);
177It isn't zero</pre>
178since 4 is not zero. If-statements can return values as well as perform actions 
179in the then and else parts. An alternative way of writing 'iszero' could have 
180been 
181<pre>> let iszero == 
182# proc(i: integer) 
183# (print( 
184# if i  = 0 
185# then "It is zero" 
186# else "It isn't zero"
187# )); </pre>
188 
189<p>This version tests the condition, and returns one or other of the strings for 
190  printing. This can only be used if both the then and else parts return values 
191  with similar specifications (in this case both sides return string constants). 
192  The version of the if-statement which does not return a value can be written 
193  with only a then-part. If the then-part returns a value there must be an else-part 
194  (otherwise what value would be returned if the condition were false?). </p>
195<h3>6. More on Procedures</h3>
196<p>Procedures can be written which return results. For instance a further way 
197  of writing 'iszero' would be to allow it to return the value of the string. 
198</p>
199<pre>> let iszero == 
200# proc(i: integer)string
201# (if i = 0 then "It is zero" 
202# else "It isn't zero"); 
203> ? "iszero";
204iszero : PROC(integer)string</pre>
205Calling it would then cause it to return the appropriate string which would then 
206be printed. 
207<pre>> iszero(0);
208It is zero </pre>
209Another example is a procedure which returns the square of its argument. 
210<pre>> let sqr ==
211# proc(i: integer)integer (i*i); </pre>
212declares sqr to be a procedure which takes an argument with type integer and returns 
213a result with type integer. The body of the procedure evaluates the square of 
214the argument i, and the result is the value of the expression. The call 
215<pre>> sqr(4); 
21616 </pre>
217<p>will therefore print out the value 16. </p>
218<p> Procedures in Poly can be written which call themselves, i.e. recursive procedures. 
219  These are declared using <strong>letrec</strong> rather than <strong>let</strong>. 
220</p>
221<pre>> letrec fact == 
222# proc(i: integer)integer 
223# (if i = 1 then 1 
224# else i*fact(i-1)); </pre>
225This is the recursive definition of the factorial function. The procedure can 
226be called by using 
227<pre>> fact(5); 
228120 </pre>
229 
230<p>which prints the result. <strong>letrec</strong> has the effect of making the 
231  name being declared available in the expression following the <strong>==</strong>, 
232  whereas <strong>let</strong> does not declare it until after the closing semicolon. 
233</p>
234<h3>7. Variables</h3>
235<p>Constants are objects whose value cannot be changed. There are also objects 
236  whose value can change, these are variables. Variables are created by declarations 
237  such as </p>
238<pre>> let v == new(0); </pre>
239The procedure 'new' returns a variable whose initial value is the argument. 
240<pre>> v; 
2410 </pre>
242A new value can be given to v by using the assignment operator. 
243<pre>> v := 3; 
244> v; 
2453 </pre>
246Thus v now has the value 3. The new value can depend on the old value. 
247<pre>> v := (v+2); </pre>
248Sets the value to be 5. The parentheses are necessary because otherwise the order 
249of evaluation would be strictly left-to-right. Variables can be of any type. 
250<pre>> let sv == new("A string"); </pre>
251 
252<p>declares sv to be a string variable. The specification of a variable is not 
253  as simple as it may seem and will be dealt with later.</p>
254<h3>8. The While Loop</h3>
255<p> It is often necessary to repeat some statements more than once. This can be 
256  done using the <strong>while</strong> statement. For instance </p>
257<pre>> let x == new(10);
258> while x <> 0
259# do
260# begin
261# print(x*x);
262# print(" ");
263# x := pred(x)
264# end; 
265100 81 64 49 25 16 9 4 1 </pre>
266prints the square of all the numbers from 10 down to 1. The body of the loop (the 
267statement after the word <strong>do</strong>) is executed repeatedly while the 
268condition (the expression after the word <strong>while</strong>) is true. The 
269condition is tested before the loop is entered, so 
270<pre>> while false
271# do print("Looping"); </pre>
272 
273<p>will not print anything.</p>
274<h3> 9. Operators</h3>
275<p>We have already seen examples of operators such as + and &. In Poly operators 
276  are just procedures whose specifications include the words <strong>infix</strong> 
277  or <strong>prefix</strong>. They are declared in a similar way to procedures, 
278  for instance </p>
279<pre>> let  sq == proc prefix (i : integer)integer (i*i); </pre>
280has declared sq as a prefix operator. It can be used like any other prefix operator: 
281<pre>> sq 3; 
2829 </pre>
283 
284<p>The difference between a prefix operator and other procedures is that the argument 
285  to a prefix operator does not need to be in parentheses. Infix operators can 
286  be defined similarly.</p>
287<h3>10. The Specifications of Types</h3>
288<p>All objects in Poly have specifications. This includes types such as string, 
289  integer and boolean. </p>
290<pre> > ? "boolean";
291boolean : TYPE (boolean)
292   & : PROC INFIX (boolean; boolean)boolean;
293   false : boolean;
294   print : PROC (boolean);
295   true : boolean; 
296   | : PROC INFIX (boolean; boolean)boolean;
297   ~ : PROC PREFIX (boolean)boolean
298END </pre>
299Types in Poly are regarded as sets of "attributes". These attributes are usually 
300procedures or constants but could be other types. The attributes of a type can 
301be used exactly like ordinary objects with the same specification. However, since 
302different types may have attributes with the same name, it is necessary to prefix 
303the name of the attribute with the name of the type separated by <strong>$</strong>. 
304<pre>> integer$print(5);
3055 </pre>
306This invokes the attribute 'print' belonging to integer and prints the number. 
307Most types have a print attribute which prints a value of that type in an appropriate 
308format. $ acts a selector which finds the attribute belonging to a particular 
309type. It is not an operator so operators always work on the selected name rather 
310than the type name. 
311<pre>> ~ boolean$true;
312false </pre>
313<h3>11. Records</h3>
314<p>Poly allows new types to be created in the same way as new procedures, constants 
315  or variables. One way of creating a new type is by making a record. A record 
316  is a group of similar or dissimilar objects. </p>
317<pre>> let rec == record(a, b: integer);</pre>
318This declares 'rec' to be a record with two components, a and b, both of type 
319integer. 
320<pre>> ? "rec";
321rec : TYPE (rec)
322   a : PROC(rec)integer; 
323   b : PROC(rec)integer;
324   constr : PROC(integer;integer)rec
325END </pre>
326'constr' is a procedure which makes a record by taking two integers, and 'a' and 
327'b' are procedures which return the 'a' and 'b' values of the record. 
328<pre>> let recv == rec$constr(3, 4); </pre>
329creates a new record with 3 in the first field (a) and 4 in the second field (b). 
330The result is given the name 'recv'. 
331<pre>> rec$a(recv);
3323
333> rec$b(recv);
3344 </pre>
335<p>show that the values of the individual fields can be found by using 'a' and 
336  'b' as procedures. They must of course be prefixed by 'rec$' to show the type 
337  they belong to.</p>
338<p>Records can be made with fields of any specification, not just constants. </p>
339<pre>> let arec == 
340# record(x:integer; p: proc(integer)integer); </pre>
341declares a record with fields x and p, x being an integer constant and p a procedure. 
342<pre>> let apply ==
343# proc(z : arec)integer
344# begin
345# let pp == arec$p(z);
346# pp(arec$x(z))
347# end; </pre>
348is a procedure which takes a constant of this record type and applies the procedure 
349p to the value x and returns the result. In fact, it is not necessary to declare 
350pp in the body of the procedure. An alternative way of writing apply is 
351<pre>> let apply ==
352# proc(z : arec)integer 
353# (arec$p(z)(arec$x(z))); </pre>
354<h3>12. Unions</h3>
355<p>Another way of constructing a type is using a 'union'. A union is a type whose 
356  values can be constructed from the values of several other types. For instance 
357  a value of a union of integer and string could be either an integer or a string. 
358</p>
359<pre>> let un == union(int: integer; str: string); </pre>
360This has created a type which is the union of integer and string. A value of the 
361union type can be constructed by using an injection function. This union type 
362has two such functions, their names made by appending 'int' and 'str' onto the 
363letters 'inj_', making 'inj_int' and 'inj_str'. ('int' and 'str' were the 'tags' 
364given in the declaration, in a similar way to fields in a record). 
365<pre>> let intunion == un$inj_int(3); </pre>
366This has created a value with type 'un' containing the integer value 3. 
367<pre>> let stringunion == un$inj_str("The string"); </pre>
368creates a value, also with type 'un', but this time containing a string. Given 
369a value of a union type it is often useful to be able to decide which of its constituent 
370types it was made from. For each of the 'tags' there is a procedure whose name 
371is made by prefixing with the letters 'is_', which returns 'true' or 'false' depending 
372on whether its argument was made from the corresponding injection function. 
373<pre>> un$is_int(intunion); true </pre>
374prints 'true' because intunion was made from 'inj_int'. However 
375<pre>> un$is_str(intunion); 
376false </pre>
377Values of the original types can be obtained by using 'projection' functions, 
378which are the reverse of the 'injection' functions. Their names are made by prefixing 
379the tags with 'proj_' to make names like 'proj_str' and 'proj_int'. 
380<pre>> un$proj_int(intunion);
3813
382> un$proj_str(stringunion); 
383The string </pre>
384print the original values. It is possible to write 
385<pre>> un$proj_str(intunion);
386Exception projecte raised </pre>
387because 'intunion' has type 'un', just like 'stringunion'. However, 'proj_str' 
388is expected to return a value with type string so when this is run it will cause 
389an error. The effect will be to raise an 'exception' called 'projecterror' which 
390means that a projection procedure was given an argument constructed using a different 
391injection procedure. 
392<pre>> let unprojstr == un$proj_str;
393> ? "unprojstr"; 
394unprojstr : PROC(un)string RAISES projecterror </pre>
395<p>shows that 'proj_str' may raise 'projecterror'. Exceptions will be dealt with 
396  in more detail later on. </p>
397<h3>13. The Type-Constructor</h3>
398<p>It is often useful to be able to construct a type which is similar to an existing 
399  one but with additional attributes. This can be done by using the type-constructor. 
400</p>
401<pre>> let nrec ==
402# type (r) extends rec;
403# let print ==
404# proc(v : r)
405# begin
406# print(r$a(v)); 
407# print(",");
408# print(r(v))
409# end
410# end;
411> ? "nrec";
412   nrec : TYPE (nrec)
413   a : PROC (nrec)integer;
414   b : PROC (nrec)integer;
415   constr : PROC (integer; integer)nrec;
416   print : PROC (nrec)
417END </pre>
418This declares 'nrec' to be a new type which is an 'extension' of an existing type 
419'rec'. It then lists the new attributes, in this case just the procedure 'print', 
420which are declared just as though they were ordinary declarations. The name 'r' 
421in parentheses which follows the word 'type' is the name for the new type within 
422the body of the type constructor, so the argument of the procedure 'print' is 
423given the type 'r'. It is important to remember that the new type is a completely 
424separate type from 'rec'. Values <em>can</em> be changed from the old to the new 
425type and vice versa, but they cannot be used interchangeably. The specification 
426of nrec is similar to that of rec except that there is now an extra procedure 
427'print'. 
428<pre>> let nrecv == nrec$constr(5,6);
429> nrec$print(nrecv);
4305,6 </pre>
431makes a value with type nrec, and prints it using the new 'print' attribute. It 
432is possible to write simply 
433<pre>> print(nrecv);
4345,6 </pre>
435because there is a procedure 'print' which looks for the 'print' attribute of 
436the type of the value given, and then calls it. This is the way integers and strings 
437are printed (they both have 'print' attributes). Many of the other operations 
438such as ':=' and '+' work in a similar way. A further alternative is to write 
439an expression. 
440<pre>> nrecv;
4415,6 </pre>
442 
443<p>In this case the compiler looks for the 'print' attribute and applies it. </p>
444<h3>14. A Further Example</h3>
445<p>This record could be extended in a different way, to make a double-precision 
446  integer. Suppose that the maximum range of numbers which could be held in a 
447  single integer was from -9999 to 9999. Then a double-precision number could 
448  be defined by representing it as a record with two fields, a high and low order 
449  part, and the actual number would have value (high)*10000 + (low). This can 
450  be implemented as follows. </p>
451<pre> > let dp ==
452# type (d) extends record(hi, lo: integer);
453# let succ ==
454# proc(x:d)d
455# begin
456# if d$lo(x) = 9999
457# then d$constr(succ(d$hi(x)), 0)
458# else if (d$hi(x) < 0) & (d$lo(x) = 0)
459# then d$constr(succ(d$hi(x)), neg(9999))
460# else d$constr(d$hi(x), succ(d$lo(x)))
461# end;
462# let pred ==
463# proc(x:d)d
464# begin
465# if d$lo(x) = neg(9999)
466# then d$constr(pred(d$hi(x)), 0)
467# else if (d$hi(x) > 0) & (d$lo(x) = 0) 
468# then d$constr(pred(d$hi(x)), 9999)
469# else d$constr(d$hi(x), pred(d$lo(x))) 
470# end;
471# let print ==
472# proc(x:d)
473# begin
474# if d$hi(x) <> 0
475# then
476# begin
477# print(d$hi(x));
478# if abs(d$lo(x)) < 10
479# then print("000")
480# else if abs(d$lo(x)) < 100
481# then print("00")
482# else if abs(d$lo(x)) < 1000
483# then print("0");
484# print(abs(d$lo(x)))
485# end
486# else print(d$lo(x))
487# end;
488# let zero == d$constr(0,0); 
489# let iszero ==
490# proc(x:d) boolean
491# ((d$hi(x) = 0) & (d$lo(x) = 0))
492# end; </pre>
493 
494<p>This is sufficient to provide the basis of all the arithmetic operations, since 
495  +,-,* etc. can all be defined in terms of succ, pred, zero and iszero.</p>
496<h3>15. Exceptions</h3>
497<p>In the section on union types above mention was made of exceptions. In the 
498  case of the projection operations of a union type an exception is raised when 
499  attempting to project a union value onto a type which was not the one used in 
500  the injection. An exception is simply a name and any exception can be raised 
501  by writing 'raise' followed by the name of the exception. </p>
502<pre>> raise somefault;
503Exception somefault raised </pre>
504raises an exception called 'somefault'. 
505<pre>> let procraises
506# == proc(b: boolean) 
507# (if b then raise afault); </pre>
508has specification 
509<pre>PROC(b: boolean) RAISES afault </pre>
510<p>Various operations, as well as projection, may raise exceptions. For instance 
511  many of the attributes of integer, such as 'succ' raise the exception 'rangeerror' 
512  if the result of the operation is outside the range which can be held in an 
513  integer constant. 'div' will raise 'divideerror' if it is asked to divide something 
514  by 0.</p>
515<p>As well as being raised exceptions can also be caught, which allows a program 
516  to recover from an error. A group of statements enclosed in brackets or 'begin' 
517  and 'end' can have a 'catch phrase' as the last item. A catch phrase is the 
518  word <strong>catch</strong> followed by a procedure. e.g. 'catch p' will catch 
519  any exception raised in the group of statements and apply p to its name. </p>
520<pre>>let proccatches ==
521# proc(excp: string) (print(excp)); 
522> begin
523# procraises(true);
524# catch proccatches
525# end;
526afault </pre>
527'proccatches' has been declared as a procedure which takes a argument of type 
528string. The exception is raised by 'procraises' and, since it is not caught in 
529that procedure it propagates back to the point at which 'procraises' was called. 
530The catch phrase catches the exception and calls the procedure with the name of 
531the exception as the argument. The catching procedure can then look at the argument 
532and decide what to do. 
533<pre>> begin
534# procraises(false);
535# catch proccatches
536# end; </pre>
537<p>does not print anything because an exception has not been raised and so the 
538  procedure is not called.</p>
539<p>If the block containing the catch phrase returns a value, then the catching 
540  procedure must return a similar value. </p>
541<pre>> let infinity == 99999;
542> let divi ==
543# proc infix(a, b: integer)integer 
544# begin
545# a div b
546# catch proc(string)integer (infinity)
547# end; </pre>
548<p>This declares 'divi' to be similar to 'div' except that instead of raising 
549  an exception it returns a large number. Since 'a div b' returns an integer value 
550  the catch phrase must also return an integer.</p>
551<h3>16. The Specification of Variables</h3>
552<p>The specification of a variable in Poly is not, as one might expect, a constant 
553  of some reference type or a separate kind of specification, but each variable 
554  is in fact a separate type. Since a type in Poly is simply a set of constants, 
555  procedures or other types, a type can be used simply as a way of conveniently 
556  grouping together objects. </p>
557<pre>> let intpair ==
558# type
559# let first == 1;
560# let second == 2
561# end; </pre>
562<p>This has declared 'intpair' to be a pair of integers containing the values 
563  1 and 2. 'intpair$first' and 'intpair$second' can be used as integer values 
564  directly. </p>
565<p> The specification of an integer variable is </p>
566<pre>TYPE
567assign: PROC(integer);
568content: PROC()integer 
569END </pre>
570A variable is a pair of procedures, 'assign' which stores a new value in the variable, 
571and 'content' which extracts the current value from it. The standard assignment 
572operator ':=' simply calls 'assign' on the variable. The compiler inserts a call 
573to 'content' automatically when a variable is used when a constant is expected. 
574'assign' and 'content' can both be called explicitly. 
575<pre>> let vx == new(5);
576> vx$assign(vx$content() + 1);
577> vx$content(); 
5786 </pre>
579As an example of a more complicated variable, suppose we wanted to write a subrange 
580variable, similar to a subrange in Pascal, which could hold values between 0 and 
58110. 
582<pre>> let sr ==
583# begin
584# let varbl == new(0);
585# type
586# let content == varbl$content;
587# let assign ==
588# proc(i: integer) 
589# (if (i < 0) | (i > 10
590# then raise rangeerror
591# else varbl$assign(i)) 
592# end
593# end; </pre>
594'varbl' is an integer variable which is initially set to 0. 'assign' checks the 
595value before assigning it to 'varbl', and raises an exception if it is out of 
596range. 'content' is just the 'content' procedure of the variable. It can be used 
597in a similar way to a simple variable. 
598<pre>> sr := 2;
599> sr;
6002
601> sr := 20;
602Exception rangeerror raised
603> sr;
6042 </pre>
605<h3>17. Specifications in Declarations</h3>
606<p>The double-precision type declared above has one drawback. The specification 
607  contains the 'hi', 'lo' and 'constr' attributes in the specification of the 
608  type which would allow someone to construct a value which had the type 'dp', 
609  but had, for instance, fields outside the range -9999 to 9999 or with different 
610  signs. This could make some of the operations fail to work. We need a way of 
611  hiding details of the internals of a type declaration so that they do not appear 
612  in the specification, and so cannot be used outside. In Poly a specification 
613  can be given to something explicitly as well as having it inferred from the 
614  declaration. </p>
615<pre>> let aconst: integer == 2; </pre>
616declares 'aconst' and forces it to have type 'integer'. The specification is written 
617in the same way as the specification of the argument of a procedure. 
618<pre>> let quote : proc(string)
619# == proc(x: string)
620# begin
621# print("`"); 
622# print(x);
623# print("'")
624# end; </pre>
625is another example of explicitly giving a specification to a value. An explicitly 
626written specification is the specification of the name which is being declared. 
627It need not be identical to the specification of the value following the '=='. 
628However it must be possible to convert the specification of the value to the explicit 
629specification (the 'context'). 
630<pre>> let avar == new(3);
631> let bconst: integer == avar; </pre>
632declares 'avar' to be an integer variable and 'bconst' to be an integer constant. 
633In the latter case the specification is necessary, otherwise 'bconst' would have 
634been a variable and would have been another name for 'avar'. The conversion of 
635a variable to a constant in order to match a given specification is one example 
636of a 'coercion' of a value to match a 'context'. There are several others which 
637can be applied depending on the particular specification. For instance the specification 
638of a procedure may be changed from an operator to a simple procedure or vice versa. 
639<pre>> let plus:
640# proc(integer;integer)integer raises rangeerror 
641# == integer$+ ; </pre>
642declares 'plus' as a procedure which is the same as the '+' attribute of integer 
643except that it is not an infix operator. 
644<pre>> plus(3,4);
6457 </pre>
646<p>The list of exceptions raised by the procedure must be included in the specification. 
647  The exception list in the specification given must include all the exceptions 
648  which may be raised, but may include others as well. A special exception name 
649  <strong>any</strong> can be used to indicate that a procedure can raise any 
650  exception. Any exception list will match a context with exception list 'raises 
651  any'. </p>
652<p> The specifications of the arguments and result must all match. </p>
653<pre>> let dble:
654# type (d)
655# succ, pred: proc(d)d raises rangeerror;
656# print: proc(d) raises rangeerror;
657# zero: d;
658# iszero: proc(d)boolean;
659# end
660# == dp; </pre>
661 
662<p>creates a new type 'dble' with the specification given. The specification is 
663  the same as that of 'dp' but with some of the attributes of dp missing. </p>
664<p> In the case of types the specification of the value must possess all the attributes 
665  of the explicit specification, but the explicit specification need not include 
666  all the attributes of the value. If a type is regarded as a set of named attributes 
667  then it is possible to take a subset of them and make them into a new type, 
668  simply by giving the new type the required specification. The specification 
669  of each attribute must itself match the specification that is given for it. 
670</p>
671<p> This mechanism provides a way of 'hiding' internal operations from the specification 
672  of a type. The specification of 'dble' above has only those attributes which 
673  are necessary to use it, and none of the operations which are used internally.</p>
674<h3>18. Types as Results of Procedures</h3>
675<p>So far we have considered procedures which take constants as arguments or return 
676  constants as results. In Poly values of any specification can be passed to or 
677  returned from a procedure. For instance </p>
678<pre>> let subrange 
679# == proc(min, max, initial: integer)
680# type (s)
681# content: proc()integer; 
682# assign: proc(integer) raises outofrange
683# end
684# begin
685# type
686# let varbl == new(initial);
687# let content == varbl$content;
688# let assign == 
689# proc(i: integer)
690# (if (i < min) | (i > max)
691# then raise outofrange 
692# else varbl$assign(i))
693# end
694# end; </pre>
695This procedure is similar to the definition of the subrange type 'sr' previously. 
696However the bounds of the type are now arguments of a procedure so their values 
697can be supplied when the program is run. Also new subrange variables can be created 
698by calling the procedure. 
699<pre>> let sv == subrange(0,10,0); </pre>
700<p>This creates 'sv' as a variable of this subrange type. As with any procedure 
701  the arguments can be arbitrary expressions provided they return results with 
702  the correct specification. </p>
703<h3>19. Types as Arguments to Procedures</h3>
704<p>Types can be passed as arguments as well as being returned from procedures. 
705</p>
706<pre>> let copy ==
707# proc(atype: type end)
708# type (t)
709# into: proc(atype)t;
710# outof: proc(t)atype
711# end 
712# begin
713# type (t) extends atype;
714# let into == t$up
715# let outof == t$down
716# end
717# end; </pre>
718This procedure takes a type and returns a type with two operations 'into' and 
719'outof'. 'up' and 'down' are procedures which are created when 'extends' is used, 
720and provide a way of converting between the original and the resulting types. 
721The specification of 'atype' merely says that it must be passed a type as an argument, 
722but since it does not list any attributes then any type can be used as an actual 
723argument (this is effectively saying that the empty set is a subset of every set). 
724The procedure can be called, giving it an actual type as argument. 
725<pre>> let copyint == copy(integer);</pre>
726The specification of the result is 
727<pre>TYPE (copyint)
728into: PROC(integer)copyint; 
729outof: PROC(copyint)integer
730END; </pre>
731The specification of copyint allows mapping between integer and copyint since 
732the type integer has been included in the specification. 
733<pre>> let copy5 == copyint$into(5);
734> copyint$outof(copy5); 
7355 </pre>
736has mapped the integer constant 5 into and out of 'copyint'. 
737<pre>> let copychar == copy(char); </pre>
738 
739<p>creates a similar type which maps between char and copychar.</p>
740<h3>20. Polymorphic Procedures</h3>
741<p>There are often cases where, in addition to passing a type as a argument, one 
742  or more values of that type are passed as well. For instance a procedure to 
743  find the second successor of a value might be written as </p>
744<pre>> let add2 ==
745# proc(atype:
746# type (t)
747# succ: proc(t)t raises rangeerror
748# end;
749# val: atype)
750# (atype$succ(atype$succ(val)));</pre>
751The specification of 'val' is that it must be a constant, and its type is 'atype'. 
752However 'atype' is also an argument to the procedure so the specification really 
753means that this procedure could be called by giving it any type with the required 
754attributes, and a constant which must be of the same type as the first argument. 
755<pre>> add2(integer, 2);
7564 </pre>
757Similarly 
758<pre>> add2(char, 'A'); C </pre>
759However 
760<pre>> add2(integer, 'A'); </pre>
761and 
762<pre>> add2(string, "A string"); </pre>
763 
764<p>both fail, in the first case because 'A' is not integer, and in the second 
765  because string does not have a successor function.</p>
766<h3> 21. Implied Arguments</h3>
767<p>Many types have a 'print' attribute which prints a constant of the type. </p>
768<pre>> let pri ==
769# proc(printable: type (t) print(t) end; val: printable)
770# (printable$print(val)); </pre>
771declares 'pri' as a procedure which takes as arguments a type and a constant of 
772that type and prints the constant using the 'print' attribute. This can be called 
773by writing 
774<pre>> pri(integer, 3); or > pri(char, 'a'); </pre>
775since both 'integer' and 'char' have a 'print' attribute. Having to pass the type 
776explicitly is really unnecessary, since it is possible for the system to find 
777the type from the specification of the constant. It would be possible for the 
778system to convert 'pri(3)' into 'pri(integer,3)' since '3' has type integer. In 
779Poly types which can be deduced from the specifications of other arguments can 
780be declared as 'implied' arguments. A argument list written in square brackets, 
781<strong>[</strong> and <strong>]</strong>, can precede the normal argument list 
782and those parameters, which must be all be types, are inferred from the other 
783actual arguments when the procedure is called. 
784<pre>> let prin == 
785# proc [printable: type (t) print: proc(t) end]
786# (val: printable)
787# (printable$print(val)); 
788  </pre>
789This can now be called by writing 
790<pre>> prin(3);
791or
792> prin("hello");</pre>
793and is in fact the definition of 'print' in the standard library. Alternatively 
794'prin' could have been declared by giving it an explicit specification and using 
795'pri'. 
796<pre>> let prin: proc[printable: type (t) print: proc(t) end]
797# (printable)
798# == pri; </pre>
799This is another form of conversion which can be made using an explicit specification. 
800Using implied parameters can simplify considerably the use of procedures with 
801types as arguments, and allow infix or prefix operators to be used in cases where 
802they could not otherwise be used. For instance, consider an addition operation 
803defined as 
804<pre>> let add == 
805# proc(summ: type (s) + : proc infix (s;s) raises rangeerror
806# end;
807# i, j: summ)summ
808# (i + j); </pre>
809would be used by writing 
810<pre>> add(integer, 1, 2);
8113 </pre>
812However, by writing 
813<pre>> let +
814# : proc infix [summ: type(s)
815# + : proc infix (s;s)raises rangeerror
816# end]
817# (i, j: summ)summ raises rangeerror
818# == add; </pre>
819 
820<p>'+' can become an infix operator, since it has only two actual arguments. Similar 
821  definitions are used for many of the other declarations in the library. </p>
822<h3>22. Literals</h3>
823<p>We have already seen how constants can be written as "Hello" or 42. These are 
824  known as literal constants, because their values are given by the characters 
825  which form them, rather than by some previous declaration. They are however, 
826  only sequences of characters, it is only by convention that "Hello" is a string 
827  constant and 42 an integer constant. This is only important when we wish to 
828  use some other definition than the 'standard' one. For instance, if the type 
829  integer were restricted to the range -9999 to 9999 then the constant 100000 
830  would be an error if it were treated as an integer. The definition of double-precision 
831  integer above, would, however, be able to represent it.</p>
832<p>In Poly, therefore, literals have no intrinsic type, they must be converted 
833  into a value by the use of a conversion routine. The compiler recognises certain 
834  sequences of characters as literals rather than names or special symbols. The 
835  three forms of literal constants recognised by the compiler are 'numbers', 'double-quoted 
836  sequences' and 'single-quoted sequences'. 'Numbers' begin with a digit and may 
837  consist of numbers or letters. </p>
838<pre>42 0H3F6A 3p14159 </pre>
839are examples of 'numbers'. 'Double-quoted sequences' are sequences of characters 
840contained in double-quotes. A double-quote character inside the sequence must 
841be written twice. 
842<pre>"Hello" "" "He said ""Hello"""</pre>
843'Single-quoted sequences' are similar to double-quoted sequences but single rather 
844than double-quotes are used. 
845<pre>'Hello' '' 'He said ''Hello''' </pre>
846When the compiler recognises one of these literals it tries to construct a call 
847to a conversion routine which can interpret it as a value of some type. For instance, 
848the standard library contains a definition of 'convertn' which the compiler calls 
849if it finds a 'number'. That definition has specification 
850<pre>PROC(string)integer </pre>
851<p>All conversion routines must have similar specifications, but the result type 
852  will differ and some exceptions may be raised. The literal is supplied as a 
853  constant of type 'string'. The conversion routine can examine the characters 
854  which form the literal and return the appropriate value. It may of course raise 
855  an exception if the characters do not form a valid value, if either the value 
856  would be out of range or if the literal contains illegal characters. </p>
857<p> There are also two other conversion routines in the standard library, 'converts' 
858  which converts double-quoted sequences into string values, and 'convertc' which 
859  converts single-quoted sequences into values of the type 'char'. These definitions 
860  can be overridden by preceding the literal by the name of a type and a $ sign. 
861  For instance </p>
862<pre>> let int == integer; 
863> let one == int$1; </pre>
864 
865<p>applies the 'convertn' routine belonging to 'int', so that 'one' has type int 
866  rather than integer. </p>
867<h3>23. Lists</h3>
868<p>Lists are a convenient example for polymorphic operations. List types can be 
869  constructed by the following procedure. </p>
870<pre>> let list ==
871# proc(base: type end) 
872# type (list)
873# car : proc(list)base raises nil_list;
874# cdr : proc(list)list raises nil_list; 
875# cons: proc(base; list)list; 
876# nil : list; 
877# null: proc(list)boolean 
878# end
879# begin
880# type (list)
881# let node == record(cr: base; cd: list);
882# extends union(nl : void; nnl : node); 
883# let cons == # proc(bb: base; ll: list)list
884# (list$inj_nnl(node$constr(bb, ll)));
885# let car ==
886# proc(ll: list)base
887# begin
888# node$cr(list$proj_nnl(ll)) 
889# catch proc(string)base (raise nil_list)
890# end;
891# let cdr ==
892# proc(ll: list)list
893# begin
894# node$cd(list$proj_nnl(ll))
895# catch proc(string)list (raise nil_list)
896# end;
897# let nil == list$inj_nl(void$empty);
898# let null == list$is_nl
899# end
900# end; </pre>
901<p>'void' is a standard type which has only one value (empty), and is used to 
902  represent the 'nil' value of the list. The list structure is made using a recursive 
903  union with each node containing a value of the 'base' type and the next item 
904  of the list, or containing a nil value. 'cons' makes a new node of the list, 
905  'car' and 'cdr' find the 'base' and 'list' parts of a node respectively, and 
906  'null' tests for the value 'nil'. 'car' and 'cdr' both trap the exception which 
907  would be raised if a projection error occurred and raise 'nil_value' in its 
908  place. </p>
909<p> A particular list type can now be created, for instance a list of integers. 
910</p>
911<pre>> let ilist == list(integer);
912> let il == ilist$cons(1, ilist$cons(2, ilist$cons(3, ilist$nil))); </pre>
913A polymorphic 'cons' function could be declared to work on lists of any base type. 
914<pre>> let cons ==
915# proc[base: type end;
916# list: type (l) cons: proc(base; l)l end]
917# (bb: base; ll: list)list # (list$cons(bb, ll)); </pre>
918It is now possible to write simply 
919<pre>> let il == cons(1, cons(2, cons(3, ilist$nil))); </pre>
920Polymorphic 'car', 'cdr' and 'null' functions can be written similarly. As further 
921examples some other polymorphic list functions are given. 
922<pre>> letrec append ==
923# proc[base: type end;
924# list: type (l)
925# car: proc(l)base raises nil_list;
926# cdr: proc(l)l raises nil_list; 
927# cons: proc(base; l)l;
928# null: proc(l)boolean end]
929# (first, second: list)list
930# ( if null(first) then second
931# else cons(car(first), append(cdr(first), second)) );
932> letrec reverse ==
933# proc[base: type end;
934# list: type (l)
935# car: proc(l)base raises nil_list;
936# cdr: proc(l)l raises nil_list; 
937# cons: proc(base; l)l;
938# nil: l;
939# null: proc(l)boolean end]
940# (ll: list)list
941# ( if null(ll) then list$nil
942# else append(reverse(cdr(ll)), cons(car(ll), list$nil)) ); </pre>
943A useful function would be one which would print the data part of a list if the 
944base type could be printed. 
945<pre>> letrec pr ==
946# proc [base: type(b) print: proc(b) end;
947# list: type(l) car: proc(l)base raises nil_list;
948# cdr: proc(l)l raises nil_list;
949# null: proc(l)boolean
950# end ]
951# (ll: list)
952# begin
953# if null(ll)
954# then print("nil") 
955# else
956# begin
957# print("( ");
958# print(list$car(ll));
959# print(". ");
960# pr(list$cdr(ll));
961# print(") ")
962# end
963# catch proc(string) () 
964# end; </pre>
965The list created above can now be printed. 
966<pre>> pr(il); 
967( 1. ( 2. ( 3. nil) ) ) </pre>
968 
969<p>Other polymorphic functions on lists can be declared in a similar way.</p>
970<h3>24. Conclusion</h3>
971<p>This document is intended as an introduction to Poly and to give some idea 
972  of the ways in which it can be used. It is not a rigorous description and various 
973  details, such as the precise checking rules for specifications, have been deliberately 
974  skated over in order to explain the language simply. A companion document, the 
975  Poly Report, is the reference for the precise details of the language. </p> 
976</p>
977</body>
978</html>
979