\documentclass{article} \begin{document} \title{\$SPAD/src/doc CompilerTutorial} \author{Timothy Daly} \newcommand{\<}{<} \maketitle \begin{abstract} We build a couple domains from scratch in order to demonstrate how to build Axiom domains using the Axiom compiler. \end{abstract} \eject \tableofcontents \eject \section{Overview} There are several sections in this tutorial, which is written to introduce concepts in Axiom programming, using a step-by-step development style and mimicking the development of a novice Axiom programmer. Section 2 uses a simple Axiom program to introduce the ideas necessary to understand how to use the compiler, how to use simple types and how to do simple output. We also discuss some differences between Axiom and the C and C++ programming languages. Section 3 introduces building an Axiom {\bf Type}. This section introduces the ideas of a {\bf Type}, signatures and export/import issues. It also introduces the split between exports and implementation. Section 4 constructs a new {\bf Type}, which we call {\tt Term}. This section introduces the ideas of representation within types and ``standard'' export lists ({\tt new}, {\tt dispose!}, {\tt access}, {\tt print}). It also introduces commenting styles and testing issues. Section 5 constructs another new type, which we call {\tt Polynomial}. This section introduces the ideas of building {\bf Type}s {\em over\/} other {\bf Type}s. It explains printing and uses this function to introduce the question of ``the right place'' to implement certain operations. It introduces the concept of local functions. It also introduces the concept of a {\bf Category}. Section 6 introduces operations {\em in\/} the {\bf Type} {\tt Polynomial}, rather than operations {\em over\/} another type. Here we introduce the polynomial arithmetic operations of {\tt +}, {\tt -} and {\tt *}. Section 7 introduces parameterized {\bf Type}s. We build a new {\tt Term} type which is more general than the previous version of {\bf Term}. We are not trying to teach programming. The reader is assumed familiar with basic programming concepts and with elementary polynomial operations, such as addition and multiplication. The reader can ignore the comparisons with C and C++ if these languages are unfamiliar. As this is a tutorial, the reader should be aware that we are making design choices motivated by simplicity or clarity rather than issues of efficiency or generality. \section{A trivial Axiom program} We will develop a simple polynomial manipulation program and illustrate the various features of the language. By the end of this tutorial you should be able to write your own Axiom programs. \subsection{Some discussion of the Axiom language for the programmer} These initial comments are intended to give those who are skilled in C and C++ an idea of the Axiom language, based on analogy. Those who are not C programmers should ignore this section. Axiom is a block structured language that is strongly typed. It follows a syntactic style similar to C. It has the following simple characteristics: \begin{itemize} \item Printing is done using the {\bf output}. For example:\\ \begin{verbatim} output "this is a number: " \end{verbatim} \item Printing several items on the same line can by done with the {\bf outputList} function. This function takes a list of objects and prints them. For example:\\ \begin{verbatim} outputList(["this is a number: ",3]) \end{verbatim} \item Assignment uses {\tt :=}. For example:\\ \begin{verbatim} a := 3 \end{verbatim} \item The conditional statement has the form: \\ {\tt if} {\it condition} {\tt then} {\it statement} {\tt else} {\it statement} \\ For example: \begin{verbatim} if a > 0 then output("positive") else output("negative") \end{verbatim} Note that you must use {\tt =} instead of {\tt ==} for equality. Note that the {\tt if then else} construct is an expression producing a value, as in: \begin{verbatim} x := if a = 0 then 1 else 2 \end{verbatim} This is the equivalent of the C/C++ expression: \begin{verbatim} x = (a == 0 ? 1 : 2) \end{verbatim} \item Iteration may be performed with the {\tt repeat} statement. For example: \begin{verbatim} for i in 1..10 repeat output(i) \end{verbatim} In Axiom you can iterate over structures in a more elegant and abstract fashion than in C, where you normally need to write loops which directly access the representation of data structures, or C++, where you need to define {\em friend} iterator classes. In Axiom every domain can provide a {\em generator} abstracting the traversal of its elements. So, for instance, you can write: \begin{small} \begin{verbatim} ls := [1,2,3,4,5] for elem in ls repeat output(elem) \end{verbatim} \end{small} \item Sequences of statements may be surrounded by braces. For example: \begin{small} \begin{verbatim} { a := 3; if a > 0 then output "positive" else output "negative" } \end{verbatim} \end{small} \item There is no {\tt main} (unless you want one). Programs are compiled as files. Top level forms (such as {\bf print}) that occur in the file are executed when the (compiled) file is run. The executable version of a file which contains: \begin{small} \begin{verbatim} #include "axllib" print \<\< "hello, world" \<\< newline; \end{verbatim} \end{small} will print \\ {\bf hello, world} \\ when it is run. This is similar to a ``compiled interpretation language'' like several new versions of Basic. \item Integers, strings and floating point numbers are not built into the language, but need to be explicitly imported. See the language description for details. \item domains and categories are similar to the C++ concept of classes and abstract classes. However, functions match {\em both\/} on the types of their arguments and the on types of the results. C++ ignores result types when trying to match function signatures. \item In contrast to C and C++, which are never indentation sensitive, the Axiom compiler can optionally take account of indentation. Using the {\tt \#pile} directive at the top of a file instructs Axiom to consider sequences of statements at the same indentation level as belonging to the same block, when braces are omitted. \end{itemize} \subsection{Signum - a first function} For the first example we will construct a trivial program to determine the sign of its argument (called the {\bf signum} function). The entire function looks like: \begin{small} \begin{verbatim} #include "axllib" signum(number: SingleInteger): String == { number > 0 => "Positive"; number = 0 => "Zero"; "Negative" } import from SingleInteger; print \<\< signum 10 \<\< newline; print \<\< signum 0 \<\< newline; print \<\< signum(-10) \<\< newline; \end{verbatim} \end{small} Axiom is a strongly typed language but, initially, the compiler does not know anything about particular types (except for a very small number of built-in types). The compiler is shipped with a type library known as {\tt axllib}. We will have the line {\tt \#include "axllib"} at the top of each file to allow access to these types. The first line of our example program is: \begin{small} \begin{verbatim} #include "axllib" \end{verbatim} \end{small} which gives us access to the types {\bf SingleInteger} and {\bf String}, both of which are {\bf Type}s (with a capital {\bf T}). \subsection{What is a Type?} {\bf Type}s (with a capital {\bf T}) are a way to create special kinds of new things in the world. Suppose we want a special kind of numbers,, such as Roman numerals (the kind you learned in school). We would need two parts to the definition of this new kinds of numbers: a way to store them in the program (called the representation) and a list of things we can do to them, such as add them, subtract them, print them etc. (called the operations). A {\bf Type} is a kind of box that packages up three things: the operations, the representation and the programs to implement the operations. Axiom programming usually consists of building new {\bf Type}s. So, when you see a new {\bf Type}, the thing you need to know is, ``What can I do with this {\bf Type}?'' or, equivalently, ``What operations are available for this {\bf Type}?'' {\bf SingleInteger} is a {\bf Type} which reflects the underlying machine implementation of integers. That is, it has a defined range based on the size of the machine's word (its representation). There are several dozen operations that we can perform --- but it is sufficient to know that they act like integers for our purposes. That is, we can add, subtract, multiply and compare them, etc. {\bf String} is a second {\bf Type} we will use. We really don't need to know how it is implemented. The only interesting operation on {\bf String}s, for our purposes, is printing. This operation is called ``{\bf \<\<}''. To build a {\bf Type} we need to know the parts of the box (remember: {\bf Type}s are boxes with three interesting parts --- the exported functions, the representation and the implementation of the exported functions). Our simple signum function is: \begin{small} \begin{verbatim} signum(number: SingleInteger): String == { number > 0 => "Positive"; number = 0 => "Zero"; "Negative" } \end{verbatim} \end{small} Let's look at the parts. The first line of this form begins: \begin{small} \begin{verbatim} signum(number: SingleInteger): String == \end{verbatim} \end{small} which is the function header (the rest of the definition is the function body). This header line reads as follows: \begin{quotation} ``We are defining a function called `{\bf signum}', which takes one argument called `{\bf number}', of {\bf Type} `{\bf SingleInteger}'. It returns a result of {\bf Type} `{\bf String}'.'' \end{quotation} The {\tt ==} marks the start of a function body. The function body is surrounded by braces ({\tt \{ \}}). Every exit from the function body {\em must\/} be of the correct return {\bf Type}. In this case, every exit from the {\bf signum} function must be of {\bf Type} {\bf String} (because we said that {\bf signum} returns a {\bf String}). Within the function body we use the ``{\bf =>}'' operator. This takes a test (something that is either true or false) on its left hand side and a value to return on its right hand side. If the test is true then we evaluate the right hand side and return its value as the value of the containing sequence. In this case the containing sequence is the program, so as soon as we find one of the tests is true we return the corresponding string as the result. The way in which ``{\bf =>}'' is used here is similar to the {\tt switch} construct in C. Defining the function will not execute it. We call the function and print the resulting value. Printing is done by the ``{\bf \<\<}'' operator. (Note that this is {\em not\/} the C++ leftshift operator). The ``{\bf \<\<}'' operator has the function header: \begin{small} \begin{verbatim} (stream: TextWriter) \<\< (thing: String): TextWriter == \end{verbatim} \end{small} This operator takes a {\bf TextWriter} on its left hand side and an object to print on its right hand side. Its result is a {\bf TextWriter} object. Since this is an infix operator (there are a few predefined infix operators in the syntax) we can cascade the ``{\bf \<\<}'' operators. (Infix means that the function is written between its arguments like the {\tt +} function rather than being written before the arguments like most functions.) Printing is thus done by: \begin{small} \begin{verbatim} print \<\< "first thing" \<\< "second thing" \<\< ... \<\< newline; \end{verbatim} \end{small} This line is executed left to right as though it had been parenthesized: \begin{small} \begin{verbatim} ((((print \<\< "first thing") \<\< "second thing") \<\< ...) \<\< newline); \end{verbatim} \end{small} An important thing to remember is that the compiler does not know anything about the particular {\bf Type}s in use, yet the meaning of each thing in our program is defined in a {\bf Type}. In our case we are using the numbers 10, 0 and -10. The compiler does not know what these things are. We intend them to be {\tt SingleInteger}s (because that's what our program takes) so we have to add the line: \begin{small}% \begin{verbatim} import from SingleInteger; \end{verbatim} \end{small} in our program to tell the compiler that {\bf SingleInteger} operations can be used. Since there isn't anything else around the 10 gets interpreted as a {\bf SingleInteger}, which is what we want. It will often be the case in Axiom programs that we need to tell the compiler to import {\bf Type}s. In our example we call the function {\bf signum} with its argument (which must be a {\bf SingleInteger}) and it returns a result of {\bf Type} {\tt String}. We call the function at the time we want to print the result. There are three lines in the example which test all possible cases. They look like: \begin{small} \begin{verbatim} print \<\< signum(10) \<\< newline; print \<\< signum(0) \<\< newline; print \<\< signum(-10) \<\< newline; \end{verbatim} \end{small} \section{Building an Axiom type} \subsection{ Properties --- a first domain} Axiom programs, like C++ programs, are normally developed as objects. The idea of an object in these languages is that there exist boxes (we call them domains, C++ calls them classes) that wrap the functions and the data representation together and hide all of the details. All we know about an object is given by the list of exports from its box, in other words the list of exports from the domain. For instance, we know we can add two {\tt SingleInteger}s because the {\bf Type} {\tt SingleInteger} exports the function {\tt +}. \begin{small} \begin{verbatim} #include "axllib" Properties: with { signum: SingleInteger -> String; ++ signum will return the sign of a number as a String } == add { signum(number: SingleInteger): String == { number > 0 => "Positive"; number = 0 => "Zero"; "Negative" } } import from SingleInteger; import from Properties; print \<\< signum(10) \<\< newline; print \<\< signum(0) \<\< newline; print \<\< signum(-10) \<\< newline; \end{verbatim} \end{small} We would like to define a new {\bf Type} --- let's call it {\tt Properties} --- with a list of functions to compute the properties of {\tt SingleInteger}s. In fact, it will have only one function, the {\bf signum} function. So, how do we define a class (um, ... domain)? Each domain has the following (simplified) form: \begin{small}% \begin{verbatim} DomainName: with { exported list of function signatures } == add { representation implementations of exported functions } \end{verbatim} \end{small} Remember that we said there are three parts to a domain. The first part is the list of all of the functions we can call from that domain. This is the ``exported list of function signatures''. For our example they look like: \begin{small}% \begin{verbatim} Properties: with { signum: SingleInteger -> String; ++ signum will return the sign of a number as a String } \end{verbatim} \end{small} {\tt Properties} is the name that we give to the domain. The {\tt with} says that we are exporting a list of function signatures. This list is surrounded by braces. The {\bf signum} line is slightly different from what we have seen before, and now reads: \begin{small}% \begin{verbatim} signum: SingleInteger -> String; \end{verbatim} \end{small} The line is a ``function signature''. The signature line is read as: \begin{quotation} ``We are exporting a function called `{\bf signum}' that will take a thing of {\bf Type} `{\bf SingleInteger}' and return a thing of {\bf Type} `{\bf String}'.'' \end{quotation} In order to define this function we use: \begin{small}% \begin{verbatim} signum(number: SingleInteger): String == \end{verbatim} \end{small} This line is the ``function header''. In the body of the domain we use function headers. The header line is read as: \begin{quotation} ``We are defining a function called `{\bf signum}' that will take a particular {\bf SingleInteger} called `{\bf number}' and return a particular {\bf String}.'' \end{quotation} So, the exports list is a list of function signatures. Note also the {\tt ++} comment that follows the function signature. In export lists the so-called ``plus-plus comments'' are related to the function signature that preceeds them. This kind of comment differs from the {\tt --} comment in that the {\tt ++} comment will show up in the documentation related to the function. Lines that contain a {\tt --} are ignored starting from the {\tt --} and ending with the newline. Similarly, lines that contain a {\tt ++} are ignored starting from the {\tt ++} and ending with the newline; however, the compiler {\em does} check the syntax of the {\tt ++} comment lines. After the export list we find the ``{\bf add} body'', which starts with the {\tt == add} clause and is surrounded by braces. The {\bf add} body contains the representation and implementation information. The {\bf add} body for our example looks like: \begin{small} \begin{verbatim} == add { signum(number: SingleInteger): String == { number > 0 => "Positive"; number = 0 => "Zero"; "Negative" } } \end{verbatim} \end{small} This is the same function definition we had earlier, except that it is now enclosed within a domain. Every exported function signature {\em must\/} have an associated implementation. However, the implementation is now ``hidden'' (encapsulated, if you like larger words) within a domain so it is not visible to the outside world. To make the function visible we need to perform three steps. We construct the signature, put it in the exports list of the domain and import the domain. When we wish to use the functions exported from the domain {\bf Properties}, we need to ``import'' from {\bf Properties}. This ensures that the functions from {\bf Properties} are in scope. Import allows control over which domains we wish to use. There might be many domains with the same signature and we wish to choose only one. \section{A new type: Term - a first representation} {\bf The complete listing for this section is at page \pageref{FirstTermRepListing}.} The {\bf signum} domain does not create a new kind of object, so we didn't specify how objects from {\bf Properties} were represented. It does not refer to itself. Domains with this structure are sometimes called ``packages'', to distinguish them from domains that refer to themselves in the export list. Leaving the {\bf Properties} domain for a while, we now will build a polynomial domain with simple exports and an internal representation. Polynomials are relatively simple things, composed of terms that are added or subtracted to form the composite polynomial. Let's look at terms. The terms are composed of products of coefficients and symbols (we are, of course, simplifying the issues but we'll come back to this later). So a term should look like: \begin{small} \begin{verbatim} 3*x \end{verbatim} \end{small} We need a representation of a symbol. Usually a symbol is just a single letter and it is sufficient for our purposes to choose the set of ascii letters as our representation of symbols. Note that this will {\em not\/} allow us to write terms like: \begin{small} \begin{verbatim} 3*x*y \end{verbatim} \end{small} This assumes that a term can contain more than one symbol (or, in general, could be composed of terms). We will revisit this design decision later. We need a representation of coefficients. These are usually called the {\em ring of coefficients} over which we build polynomials. The ring has certain operations defined on it. We will ignore this for the moment and choose {\tt SingleInteger}s (machine integers) as our coefficients. Note that this will {\em not\/} allow us to write the polynomial: \begin{small} \begin{verbatim} (2/3)*x \end{verbatim} \end{small} as (2/3) is not a {\bf SingleInteger}. Thus we will need to revisit this design decision if we need to divide polynomials. \subsection{Rep, the representation domain} Now that we have made those decisions we need a representation for terms. A {\bf Term} can be stored as a record composed of a coefficient and a symbol. This is written in Axiom as: \begin{small} \begin{verbatim} Rep == Record(coef:SingleInteger, var:Character); \end{verbatim} \end{small} This is a new construct for several reasons. The ``{\bf ==>}'' notation defines a macro. Every occurrence of {\tt Rep} will be replaced by the form on the right side of the arrow. {\bf Record}s form a {\bf Type} that is similar to C ``structs''. They have a list of fields (in this case, {\tt coef} and {\tt var}) and each field has its own {\bf Type} (in this case, {\tt SingleInteger} and {\tt Character}). {\bf Record}s are a useful way of combining many different {\bf Type}s into one data structure. By convention in Axiom, {\tt Rep} is used to define the representation of a domain. Such a representation may be defined using either a macro definition, as shown, or a constant definition, with {\tt ==} instead of {\tt ==>}. It is not essential to define a representation for a domain but it is generally useful, as there are two macros which work specifically on representations. Contrast what a user sees as the representation of your {\bf Type} with how the type is implemented: in this case, we have defined our {\em representation\/} (how a term will actually be stored) as a {\bf Record} --- however, the user will see terms as {\bf Term}s, that is, as a brand new {\bf Type} in the world. We will, at times, need to move between the view of the data as a {\bf Term} and the view of the data as a {\bf Record}. The macro {\tt rep} takes a {\tt Rep} (in this case, a {\bf Record}) and views it as a domain type (in this case, a {\bf Term}). The macro {\tt per} goes the other way: it takes a domain type (a {\bf Term}) and views it as a {\bf Rep} (a {\bf Record}). So: \begin{small}% \begin{verbatim} per: Record(coef: SingleInteger, var: Character) -> Term; rep: Term -> Record(coef: SingleInteger, var: Character); \end{verbatim} \end{small} Sometimes we have a {\bf Record} and we need a {\bf Term} (such as when we return a result from a function) so the correct form is: \begin{small}% {\bf per(}{\em recordobject\/}{\bf )} \end{small} and sometimes we have a {\bf Term} (such as when the user has called one of our exported functions) and we need to reach into the {\bf Term} object to get the parts. So the correct form is: \begin{small}% {\bf rep(}{\em termobject\/}{\bf )} \end{small} This will (hopefully) become clear as we progress with the example. \subsection{Importing the Rep} Once we have chosen the representation we must tell the compiler to bring the functions related to that representation into the world (into ``scope''), so that we can use the functions from {\bf Record} on our representation. The most common method of doing this is to follow the {\tt Rep} macro definition with the line: \begin{small} \begin{verbatim} import from Rep; \end{verbatim} \end{small} Since {\tt Rep} is a macro that expands into \begin{small} \begin{verbatim} Record(coef: SingleInteger, var: Character) \end{verbatim} \end{small} this line {\em really\/} reads (after macro expansion in the compiler): \begin{small} \begin{verbatim} import from Record(coef: SingleInteger, var: Character); \end{verbatim} \end{small} This will import operations from the value of {\tt Rep}, which allows access to the interior of the object. \subsection{ Choosing our export list} Another early step in developing a new domain is the choice of functions to export. These define the {\bf Type} the user sees. {\em How} the {\bf Type} is represented is much less important than {\em what} we can do with the {\bf Type}, at least from the user's point of view. When you construct a new {\bf Type}, the choice of representation {\em is} an important issue and will impact the efficiency of the resulting code. You have complete freedom about what functions you export from your domain. What follows is a list that suggests useful exports for every domain. For various reasons you might decide not to implement these functions. We recommend these because users of your domain will expect to perform at least these operations. It is reasonable that new domains have the following functions: \begin{description} \item[new] which constructs a new instance of the domain, \item[dispose!] which destroys an instance, \item[{\tt \<\<}] which prints an instance, \item[{\em accessors}] which allow access to the parts of an instance. \end{description} In the description of the domain there is a special symbol, {\tt \%} which refers to ``the type being defined''. Starting with these as the primitive functions we'll develop them one by one. \subsection{New --- the constructor function} The function {\tt new} should take the parts of a domain representation and construct a new instance of the domain from those parts. For example, the instance {\tt 3} is a particular example of the type {\bf SingleInteger}. nSince we are working with the domain {\bf Term} we need a function, {\tt new}, that takes a {\bf SingleInteger} and a {\bf Character} (the two things we need to stick into our {\bf Record(coef: SingleInteger, var: Character))} and returns an instance of the type {\bf Term}. The signature of the {\tt new} function is: \begin{small} \begin{verbatim} new: (SingleInteger, Character) -> %; \end{verbatim} \end{small} That is, the function {\tt new} takes two arguments, a {\bf SingleInteger} and a {\bf Character}, and returns a new instance of this domain (in this case, the domain {\bf Term}). Note that we are using {\tt \%} to mean ``this domain''. So, for example: \begin{small} \begin{verbatim} new(10, char "x") \end{verbatim} \end{small} returns a new {\bf Term}. Since we haven't decided how to print {\bf Term}s yet we cannot show what the term looks like; however, this defines the term {\tt 3*x}. Now that we know the signature, let's look at the implementation. In the {\bf add} body we have the following code: \begin{small} \begin{verbatim} new(number: SingleInteger, variable: Character): % == per([number, variable]); \end{verbatim} \end{small} This says that we are implementing the function {\tt new}. It takes two \linebreak arguments: number is a {\bf SingleInteger} and variable is a {\bf Character}. We return a {\tt \%} (the magic symbol again). That is, we return an instance of ``this domain'' (which is {\bf Term}). So we have to write a function that takes a number and a variable and constructs a {\bf Record(coef: SingleInteger,} {\bf var: Character)}. The {\tt [number,variable]} will do this. However, the returned result is {\em not\/} supposed to be a {\bf Record} (which is our {\tt Rep}) but should be a {\bf Term} (which is our {\bf Type}). The magic macro that changes a {\tt Rep} to a {\tt \%} is {\tt per}. So the final result of {\tt per([number,variable])} is a {\bf Term}. \subsection{Dispose! --- destroying an instance } The function {\tt dispose!} frees up the storage taken up by instances of this domain. In this case, we will ignore the storage issues and return nothing, which is written as {\tt ()}. So the signature is: \begin{small} \begin{verbatim} dispose!: % -> (); \end{verbatim} \end{small} Axiom, by default, includes a ``garbage collector'' which reclaims storage that you are no longer using. This strategy should be sufficient to handle storage needs for simple programs. We will comment that for efficiency reasons it is probably a good idea to have {\tt dispose!} add discarded items to a list and let {\tt new} pick discarded items from this list instead of always allocating extra storage. The {\tt new} and {\tt dispose!} operations for the primitive array and record types in the basic Axiom library do this, so if you implement your operations in terms of these, this is what you will get. This is an excellent efficiency mechanism if used properly but can be dangerous if the storage is being pointed to by something else. Don't hold on to all the storage you ever use as the program will probably grow too large. The benefits of this technique outweigh the complexity. We're ignoring all of these issues for now. If we look in the {\bf add} body, we will find the code that implements the {\tt dispose!} function. It looks like: \begin{small} \begin{verbatim} dispose!(ignore: %): () == {} \end{verbatim} \end{small} That is, it takes a {\tt \%} (in this case, a {\bf Term}) as an argument and returns no result. \subsection{{\tt \<\<} --- printing the Type} Above, we constructed an instance of term. It looked like: \begin{small} \begin{verbatim} new(10, char "x") \end{verbatim} \end{small} Now we will walk through the steps of printing this term. To print this term we would make the call: \begin{small} \begin{verbatim} print \<\< new(10, char "x") \end{verbatim} \end{small} Printing is done using ``{\bf \<\<}'', similar to the C++ convention. The signature of this is already defined for {\tt Record}s, {\tt SingleInteger}s and {\bf Character}s (the types we are using in our representation). However, it is {\em not\/} defined for instances of our type, {\bf Term}. The ``{\bf \<\<}'' function takes a {\bf TextWriter} as its left argument (``{\bf \<\<}'' is infix) and an instance of {\bf Term} as its right argument and returns an instance of {\bf TextWriter} as its result. The symbol {\tt print} in the above call is a {\bf TextWriter}. So our signature is: \begin{small} \begin{verbatim} \<\<: (TextWriter, %) -> TextWriter; \end{verbatim} \end{small} (Notice the {\tt \%}. This is a shorthand meaning ``the current domain''. In this case we are talking about the domain {\bf Term}, so {\tt \%} means {\bf Term}, similar to the usage of {\tt this} in C++. However, you will see this symbol show up many times in Axiom code and it has a meaning based on what domain you are defining. It is {\em important} to know {\em which} {\tt \%} you are talking about. Be very careful about the meaning of this symbol.) If we look in the {\bf add} body for the implementation we find: \begin{small} \begin{verbatim} (port: TextWriter) \<\< (term1: %): TextWriter == { port \<\< rep(term1).coef; port \<\< "*"; port \<\< rep(term1).var } \end{verbatim} \end{small} This says that we have a function ``{\bf \<\<}'' that takes a {\bf TextWriter} and a {\tt \%} (in this case, a {\bf Term}) and returns a {\bf TextWriter}. \subsubsection{The second line} We start out with our hands on a {\bf Term} (in the variable called {\bf term1}) which we want to print. First we use the form: \begin{small} \begin{verbatim} rep(term1) \end{verbatim} \end{small} to view the {\bf term1} variable as our {\tt Rep} (in this case, a {\bf Record}). Then we reach into the record to get the {\bf coef} information with: \begin{small} \begin{verbatim} rep(term1).coef \end{verbatim} \end{small} This is a {\bf SingleInteger} (because that's what we said we would put into our {\bf Record}). Now we call a function to print the {\bf SingleInteger}: \begin{small} \begin{verbatim} port \<\< rep(term1).coef; \end{verbatim} \end{small} This uses the ``{\bf \<\<}'' function from {\bf SingleInteger} which has the signature: \begin{small} \begin{verbatim} \<\<: (TextWriter, SingleInteger) -> TextWriter \end{verbatim} \end{small} After all of this the first line of the program prints: \begin{small} \begin{verbatim} 10 \end{verbatim} \end{small} \subsubsection{The third line} The third line of the program calls \begin{small} \begin{verbatim} \<\<: (TextWriter, String) -> TextWriter \end{verbatim} \end{small} and prints a {\tt *} string. The printed line {\em now\/} looks like: \begin{small} \begin{verbatim} 10* \end{verbatim} \end{small} \subsubsection{The fourth line} Again we need to use \begin{small} \begin{verbatim} rep(term1) \end{verbatim} \end{small} to view the term1 variable as our {\tt Rep} (in this case, a {\bf Record}). Then we reach into the record to get the var information with: \begin{small} \begin{verbatim} rep(term1).var \end{verbatim} \end{small} This is a {\bf Character} (because that's what we said we would put into our {\bf Record}). Now we call a function to print the {\bf Character}: \begin{small} \begin{verbatim} port \<\< rep(term1).var; \end{verbatim} \end{small} This uses the ``{\bf \<\<}'' function from {\bf Character} which has the signature: \begin{small} \begin{verbatim} \<\<: (TextWriter, Character) -> TextWriter \end{verbatim} \end{small} After all of this the line {\em now\/} looks like: \begin{small} \begin{verbatim} 10*x \end{verbatim} \end{small} Notice that we have {\em not\/} put a newline character in our printing routine. The polynomial domain will print many terms and they need to be strung out on a single line so we let someone else worry about how the line is formatted and concentrate on how a term should look on a line. We will have much more to say about ``{\bf \<\<}'' issues and printing later in this tutorial. For now it is enough to know that if we add the above signature to the export list and a ``{\bf \<\<}'' function to our ``{\bf add} body'' then we can control the way a {\bf Term} is printed. \subsection{Name overloading} Whew! That is harder to explain than it is to program. However, we are using many different ``{\bf \<\<}'' functions and they all have the same name. This is called {\em name overloading}. In a different language that doesn't support name overloading we would have to have named the functions with different names like: \begin{small} \begin{verbatim} printTerm printSingleInteger printCharacter printString \end{verbatim} \end{small} We {\em could\/} do that here but it is much more natural to use a single function name for the task we are trying to do rather than the type we are trying to print. Most computer programming languages let you do this for a {\em very} small number of names, or have predefined overloaded operations, but do not allow the addition of new operations. For example, it is usually the case that you can write: \begin{tabular}{llll} \ & y=3*4 & which uses & {\bf *:(Integer,Integer) -> Integer;} \\ and & y=3.0*4.0 & which uses & {\bf *:(Float, Float) -> Float;} \\ and & y=3*4.0 & which uses & {\bf *:(Integer, Float) -> Float;} \end{tabular} but you cannot overload most other function names in other languages. \subsection{Accessing the representation} Since we have a record of two fields, {\tt coef} and {\tt var}, we'd like the world to be able to look inside and access the fields without violating the encapsulation. There is no need for users to know that {\bf Term}s are implemented as {\bf Record}s, only that there are two parts. The accessors need to reach inside a particular {\bf Term} so each accessor takes a {\bf Term} as its argument and return the part as its result. \begin{small} \begin{verbatim} coef: Term -> SingleInteger; var: Term -> Character; \end{verbatim} \end{small} In the ``{\bf add} body'' we find the implementations: \begin{small} \begin{verbatim} coef(term1: %): SingleInteger == rep(term1).coef; \end{verbatim} \end{small} that is, {\tt coef} takes a {\bf Term} (verb"term1"), pretends it is a {\bf Record}, reaches into the record to get the {\bf coef} field (which is a {\bf SingleInteger}) and returns it; \begin{small} \begin{verbatim} var(term1: %): Character == rep(term1).var; \end{verbatim} \end{small} {\tt var} takes a {\bf Term} ({\bf term1}), pretends it is a {\bf Record}, reaches into the record to get the {\bf var} field (which is a {\bf Character}) and returns it. \subsection{A word about testing} Every exported function should be tested. You will notice in the examples that follow we try to find boundary cases for all of the exported functions. It is a reasonable idea to leave the test cases in the original source file for later use. Changes to the source file can be tested easily by uncommenting the test cases. The commented test cases are useful documentation for the end user, who needs to know how to use various functions. The easiest method of adding test cases and commenting them out is to surround them with the compiler directive: \begin{small} \begin{verbatim} #if TEST testcase1 testcase2 ... #endif \end{verbatim} \end{small} If you compile the file and use the compiler switch {\bf -DTEST} you will compile all of the test cases. Running the file will run the test cases. Everything between the compiler directives ({\tt \#if} .. {\tt \#endif}) will be compiled. If you compile the file without this compiler switch, you will compile the file without the test cases. Running the file will not run the tests. Everything between the compiler directives will be commented out. \subsection{Listing} \label{FirstTermRepListing} \begin{small} \begin{verbatim} #include "axllib" Term: with { new: (SingleInteger, Character) -> %; dispose!: % -> (); \<\<: (TextWriter, %) -> TextWriter; coef: % -> SingleInteger; var: % -> Character; } == add { Rep == Record(coef: SingleInteger, var: Character); import from Rep; new(number: SingleInteger, variable: Character): % == per([number, variable]); dispose!(ignore: %):() == {} (port: TextWriter) \<\< (term1: %): TextWriter == { port \<\< rep(term1).coef; port \<\< "*"; port \<\< rep(term1).var } coef(term: %): SingleInteger == rep(term).coef; var(term: %): Character == rep(term).var; } import from SingleInteger; import from Character; import from Term; term1 := new(3, char "x"); print \<\< term1 \<\< newline; print \<\< coef term1 \<\< newline; print \<\< var term1 \<\< newline; dispose! term1; \end{verbatim} \end{small} \section{A new Type: Polynomial} {\bf The complete listing for this section is at page \pageref{PolynomialListing}.} \subsection{Deciding on a representation} We plan to construct our first polynomial. It will consist of {\bf Term}s added together (we will ignore the signs of the terms for now). Since polynomials consist of a variable number of terms, we will need to mark each term with its respective power. We could do this in two ways... Each term could have an explicit power attached. This is called a sparse representation because not all of the terms in a polynomial need to be present. We do not need to keep zero terms in a sparse representation. An alternative is to represent each term by its position in a data structure. The position is the power of the term. This is called a dense representation. Dense representations need a term in every position of the representation even if the term is zero. In general, a sparse representation is cheaper to store and harder to manipulate. Since this is a tutorial we will use a dense representation. This will certainly make it expensive to store $x^{1000}$ --- but should simplify the code. The representation will be an {\bf Array} long enough to hold the terms. Array element 1 holds the constant term, array element 2 holds the $x^1$ power term, etc. The array will be one longer than the highest power in the polynomial. So we need the lines: \begin{small} \begin{verbatim} Rep == Array Term; import from Rep; \end{verbatim} \end{small} \subsection{The type tower --- \\ a closer look at Term} Another important fact is that we've chosen {\bf Array(Term)} as our representation. This assumes that the {\bf Type} constructor {\tt Array} will accept {\bf Term} as a type it can use for elements of arrays. However, when we look at the definition of the {\bf Array} (in {\bf array.as}, in your Axiom {\bf samples/libaxllib} directory --- see \ref{asugManifest}) we see the following domain definition: \begin{small} \begin{verbatim} Array(S: BasicType): ExtensibleArrayCategory S \end{verbatim} \end{small} This definition tells us that the argument to {\bf Array} must be of type {\bf BasicType}. We cannot use this definition of {\bf Array} to build arrays of things that do not satisfy the definition of {\bf BasicType}. When we try to do so, the compiler will see the definition: \begin{small} \begin{verbatim} Array Term \end{verbatim} \end{small} and complain that {\bf Term} is not of {\bf Type} ``{\bf BasicType}''. So we have to change the domain header for {\bf Term} to declare that {\bf Term} is a {\bf BasicType}. Our old domain header said: \begin{small} \begin{verbatim} Term: with { \end{verbatim} \end{small} and we change it to read: \begin{small} \begin{verbatim} Term: BasicType with { \end{verbatim} \end{small} which says that {\bf Term} is a {\bf BasicType} with some additional functions. Now when we try to compile it the compiler says: \begin{small}% \begin{verbatim} Term is missing the following exports: =: (%, %) -> Boolean; ++ Equality test. sample: %; ++ Example element. \end{verbatim} \end{small} Oh, bother. The compiler is unable to accept that {\bf Term} is a {\bf BasicType} because {\bf Term} does {\em not\/} provide all of the required functions. To build up a data structure like {\bf Array(Term)} (which we call a {\em type tower} in Axiom) each {\bf Type} in the tower has to provide all of the functions expected by the next step in the tower. Why? Well, {\bf Array} needs to be able to decide if two elements are equal. Everything that is a {\bf BasicType} {\em must\/} have an {\tt =} function so that Array knows that it has a way to decide if two array elements are equal without knowing anything about an array element. All it has to do is get the two array elements and call {\bf equal} from their {\bf Type}. {\bf Term}, as we have defined it so far, does {\em not\/} implement an {\tt =} function. \subsection{BasicType} Let's look at {\bf BasicType} for a moment (in {\bf axlcat.as} in theAxiom \linebreak {\bf samples/libaxllib} directory --- see \ref{asugManifest}). {\bf BasicType} has the following definition: \begin{small} \begin{verbatim} define BasicType: Category == with { =: (%, %) -> Boolean; ++ Equality test. ~=: (%, %) -> Boolean; ++ Inequality test. \<\<: (TextWriter, %) -> TextWriter; ++ Basic output. \<\<: % -> TextWriter -> TextWriter; ++ Basic output. sample: %; ++ Example element. hash: % -> SingleInteger; ++ Hashing function. default (x: %) ~= (y: %): Boolean == not (x = y); default hash(x: %): SingleInteger == (0$Machine)::SingleInteger; default (\<\<)(x: %)(p: TextWriter): TextWriter == p \<\< x; } \end{verbatim} \end{small} n{\bf BasicType} is a type called a {\bf Category}, or metaclass. For something to be a {\bf BasicType} it {\em must\/} implement the functions that are in the export list. {\bf Term} does not implement the following functions: {\tt =}, {\tt \~{}=}, ``{\bf \<\<}'', {\tt sample} and {\tt hash}. Without these, we cannot consider {\bf Term} to be a {\bf BasicType}. Look carefully at this definition. There are three functions at the bottom that are marked as {\tt default}. That means that, if the domain (in this case {\bf Term}) does {\em not\/} implement these functions, the default definitions from the {\bf Category} will be used. So, we do not need to implement the functions {\tt \~{}=}, {\tt hash} and ``{\bf \<\<}.'' (Well, almost....) Notice also that there are {\em two} definitions of ``{\bf \<\<}''. They have different signatures. That means that there are two different functions with the same name. This is not a problem --- in fact, it is a feature. Axiom will only consider a function call to match a function definition {\em if} the name, the type of each argument {\em and} the type of the result are the same. So, even if we have two functions with the same name, it is clear that the rest of the signature is different and so they are different. \subsection{Implementing equality (=) in Term} Ultimately, we need to do several things: we need to implement the {\tt =} function for the domain {\bf Term}; we need to define {\tt sample}; we need to export both functions from {\bf Term} and we need to declare that {\bf Term} is now fulfilling the contract of {\bf BasicType}. Let's do them one at a time. The signature that we need to export for the function {\tt =} looks like: \begin{small} \begin{verbatim} =: (%, %) -> Boolean; \end{verbatim} \end{small} We need to be able to compare two {\bf Term} objects to decide whether they are equal. In this case, a working definition might be that two {\bf Term} objects are equal if and only if the coefficients are equal and the variables are equal. Notice that we use the definition of equality defined by the types we used to build {\bf Term}. This is an important rule of composing and constructing domains. This function implementation needs to be put in the {\bf add} body of {\bf Term}: \begin{small} \begin{verbatim} (term1: %) = (term2: %): Boolean == { coef term1 ~= coef term2 => false; var term1 ~= var term2 => false; true } \end{verbatim} \end{small} This says that we have an infix function {\tt =} which takes two arguments: {\tt term1} of {\bf Type} {\tt \%} (in this case, {\bf Term}) and {\tt term2} of {\bf Type} {\tt \%} (in this case, {\bf Term}) and returns a {\bf Boolean}.% We implement it as follows: The second line calls the function with signature: \begin{small} \begin{verbatim} ~=: (SingleInteger, SingleInteger) -> Boolean \end{verbatim} \end{small} because {\tt coef(term1)} and {\tt coef(term2)} both return {\tt SingleInteger}s and the ``{\bf =>}'' needs a {\bf Boolean} result on its left hand side. If they are {\em not} equal then the terms cannot be equal and we return {\bf false}. The third line says call the function with signature: \begin{small} \begin{verbatim} ~=: (Character, Character) -> Boolean \end{verbatim} \end{small} because {\tt var(term1)} and {\tt var(term2)} both return {\bf Character} and the ``{\bf =>}'' needs a {\bf Boolean} result on its left hand side. If they are {\em not} equal then the terms cannot be equal and we return {\bf false}. The fourth line (if we get to it) says that we have passed all of the tests so the terms must be equal and we return {\bf true}. \subsection{Implementing sample in Term} The second signature we need to implement is: \begin{small} \begin{verbatim} sample: %; \end{verbatim} \end{small} That is, we need to return a sample element of the domain. A reasonably harmless sample element would be one with a 0 coefficient since it would never show up in the printed representation. Alternatively, we could return an element with the 1 coefficient and the variable {\tt x}. In general, the sample element should be the easiest (in some sense) to compute, because no user of the domain can rely on specialised properties of the sample, such as one-ness or emptyness. For now, let's return the 0 element. Since the variable doesn't matter, we'll use {\tt x}. \subsection{Fulfilling the contract} The next step would be to add both signatures to the export list of {\bf Term} --- but it turns out that we don't have to do this. Look carefully at the definition of {\tt =} and {\tt sample} in {\bf BasicType}. The signatures read: \begin{small} \begin{verbatim} =: (%, %) -> Boolean; sample: %; \end{verbatim} \end{small} Notice that they use {\tt \%}, not {\bf BasicType}. Remember that {\tt \%} means ``the current domain''. So the signature that {\bf BasicType} exports is automatically valid for {\bf Term} when used in {\bf Term}. We only need to implement these functions. Finally, as we have fulfilled the contract of being a {\bf BasicType}, we declare that we are a {\bf BasicType}. This allows {\bf Array(Term)} to be constructed. The new definition line and exports for the {\bf Term} domain look like: \begin{small} \begin{verbatim} Term: BasicType with { new: (SingleInteger, Character) -> %; dispose!: % -> (); \<\<: (TextWriter, %) -> TextWriter; coef: % -> SingleInteger; var: % -> Character; } \end{verbatim} \end{small} But we get all of the signatures exported from {\bf BasicType} in addition so the {\em real} exports are those from {\bf BasicType} {\em and} {\bf Term} (that is, we can call all of these functions on {\bf Term}s, even though it does not look as if they are exported from {\bf Term}): \begin{small} \begin{verbatim} =: (%, %) -> Boolean; ++ Equality test. ~=: (%, %) -> Boolean; ++ Inequality test. \<\<: (TextWriter, %) -> TextWriter; ++ Basic output. \<\<: % -> TextWriter -> TextWriter; ++ Basic output. sample: %; ++ Example element. hash: % -> SingleInteger; ++ Hashing function. new: (SingleInteger, Character) -> %; dispose!: % -> (); \<\<: (TextWriter, %) -> TextWriter; coef: % -> SingleInteger; var: % -> Character; \end{verbatim} \end{small} Notice that we also get {\tt \~{}=}, {\tt hash} and ``{\bf \<\<}'' implementations for free from {\bf BasicType}. We have the option of providing our own definition which will override the default definition, but we do not need to do this at the moment. That is, we can say: \begin{small} \begin{verbatim} new(10, char "x") ~= new(10, char "x") \end{verbatim} \end{small} (which is false, by our definition) but we {\em don't} have to implement this function in the {\bf add} body of {\bf Term}. It is {\em inherited\/} from being a default in {\bf BasicType}. That's why we said \begin{small} \begin{verbatim} Term: BasicType with { \end{verbatim} \end{small} We are saying that we want all of the signatures from {\bf BasicType} {\em and} that we provide any implementations that we need to be a {\bf BasicType}. This type checking of export lists is a fundamental feature of the Axiom language. Since {\bf Term} is a {\bf BasicType} we know that it will have certain features and we can depend on this fact. In particular, we know that we can compare any two {\bf Term}s for equality (because {\bf Term} is a {\bf BasicType} and all {\bf BasicType}s have a definition for equality). \subsection{Polynomial --- the definition} As usual, we need the minimum functions for a domain: \begin{description} \item[new] which constructs a new instance of the domain, \item[dispose!] which destroys an instance, \item[{\tt \<\<}] which prints an instance, \item[{\em accessors}] which allow access to the parts of an instance. \end{description} The {\tt new} function takes a list of type {\bf Term}, and returns an instance of a {\bf Polynomial}. The signature is: \begin{small} \begin{verbatim} new: List(Term) -> %; \end{verbatim} \end{small} \vbox{ Notice that the {\tt \%} in this signature refers to the current domain, \linebreak {\bf Polynomial}, not to the domain {\bf Term} we were using above. Within a domain definition it always refers to the current domain. The {\tt dispose!} function does nothing interesting at this time and returns nothing. \begin{small} \begin{verbatim} dispose!: % -> (); \end{verbatim} \end{small} The ``{\bf \<\<}'' function has the same signature as the ``{\bf \<\<}'' function from the {\bf Term} domain but the {\tt \%} refers to {\bf Polynomial}: \begin{small} \begin{verbatim} \<\<: (TextWriter, %) -> TextWriter; \end{verbatim} \end{small} \subsection{Printing --- a digression} Printing polynomials is a mildly interesting issue. Let's do a step by step code development of the ``{\bf \<\<}'' function. We need to understand the requirements of the ``{\bf \<\<}'' function a little better. The standard function header is: \begin{small} \begin{verbatim} (stream: TextWriter) \<\< (poly: %): TextWriter \end{verbatim} \end{small} which means that we expect a {\tt stream} as our left hand argument (the ``{\bf \<\<}'' operator is infix) and a {\tt poly} object as our right hand object. Within the body of the function, printing is done by referring to the {\bf stream}: \begin{small} \begin{verbatim} stream \<\< poly \<\< newline; \end{verbatim} \end{small} this will print the {\bf poly} on the {\bf stream}, followed by a newline. It is normal to return {\bf stream} as the last thing in the body of the ``{\bf \<\<}'' function. A first cut is to just print each term of the polynomial (except the last) followed by a {\tt +} sign, thus: \begin{small} \begin{verbatim} (stream: TextWriter) \<\< (poly: %): TextWriter == { size: SingleInteger := #(rep(poly)); for i in 1..(size-1) repeat stream \<\< poly.i \<\< "^" \<\< (size - i) \<\< " + "; stream \<\< poly.size } \end{verbatim} \end{small} When we do this our polynomial will look something like: \begin{small} \begin{verbatim} 3*x^2 + 2*x^1 + 1*x^0 \end{verbatim} \end{small} which is correct but somewhat ugly. } First we simplify the printing of the zeroth order term. Since anything to the zero power is 1 that term should be printed as {\bf 1}. The change we need to make is to just print the {\bf coef} of the last term. Since {\tt poly.size} is of type {\bf Term} we can use the function {\tt coef} from {\bf Term} directly: \begin{small} \begin{verbatim} (stream: TextWriter) \<\< (poly: %): TextWriter == { size: SingleInteger := #(rep(poly)); for i in 1..(size-1) repeat stream \<\< poly.i \<\< "^" \<\< (size - i) \<\< " + "; stream \<\< coef(poly.size) } \end{verbatim} \end{small} Next we note that the {\bf $x^1$} notation is unnecessary, so we change the index and print this term as {\tt x}: \begin{small} \begin{verbatim} (stream: TextWriter) \<\< (poly: %): TextWriter == { size: SingleInteger := #(rep(poly)); for i in 1..(size-2) repeat stream \<\< poly.i \<\< "^" \<\< (size-i) \<\< " + "; stream \<\< poly.(size-1) \<\< " + " stream \<\< coef(poly.size) } \end{verbatim} \end{small} A third change is that we do not want to print terms of the form {\bf $0*x^n$}. That is, if the term has a zero {\bf coef} we want to skip the printing. We could reach into the term by asking for the {\bf coef}, but there is another way to do this. Asking if a term is zero is an interesting question of anything of type {\bf Term} so we will change {\bf Term} to export a zero? function. It is a trivial change but a better programming choice. So, the following signature gets added to {\bf Term}: \begin{small} \begin{verbatim} zero? % -> Boolean; \end{verbatim} \end{small} and we can now use it in {\bf Polynomial}'s implementation of ``{\bf \<\<}'' thus: \begin{small} \begin{verbatim} (stream: TextWriter) \<\< (poly: %): TextWriter == { size: SingleInteger := #(rep(poly)); for i in 1..(size-2) repeat if not zero?(poly.i) then stream \<\< poly.i \<\< "^" \<\< (size - i) \<\< " + "; if not zero?(poly.(size-1)) then stream \<\< poly.(size-1) \<\< " + "; if zero?(poly.size) then stream \<\< 0 else stream \<\< coef(poly.size) } \end{verbatim} \end{small} This will now skip printing terms whose coefficient is zero. However, it has a poor hack for handling the {\bf $x^0$} term. The problem is that we print trailing {\tt +} signs after every term except the last. What happens if we decide {\em not\/} to print the last term (because it is zero)? Well, if we print nothing we have a dangling {\tt +} sign. So, we cheat and print 0. We can do better. The problem is with the program design. It prints a {\tt +} without knowing that there will be a trailing term. It needs to check {\em all} trailing terms for nonzero to decide to print a {\tt +}. This could be done but is inefficient. A better hack is to print a prefix {\tt +} whenever we print a term (except the first, of course). So, another shot at it follows: \begin{small} \begin{verbatim} (stream: TextWriter) \<\< (poly: %): TextWriter == { size: SingleInteger := #(rep(poly)); prefix: String := ""; for i in 1..(size-2) repeat if not zero?(poly.i) then { stream \<\< prefix \<\< poly.i \<\< "^" \<\< (size - i); prefix := " + " } if not zero?(poly.(size-1)) then { stream \<\< prefix \<\< poly.(size-1); prefix := " + " } if not zero?(poly.size) then stream \<\< prefix \<\< coef(poly.size); stream } \end{verbatim} \end{small} And now, another problem ... (these all fall under the universal law: ``There is no such thing as a simple job'') ... what happens if the whole polynomial contains nothing but zero coefficients? The code given above will print nothing, but should print a {\tt 0}. We can get this situation if we subtract a polynomial from itself. Each term of the result will be zero and the whole list of terms will be zero. We could hack the code in several ways. The simple fix is to check to see if the prefix string is still blank at the end of printing. If that is the case and the trailing term is zero then we didn't print anything so we can print a {\tt 0}. Simple but ugly. The ugliness comes into play because this function {\em knows} what the zero polynomial looks like. Yes, it is part of the implementation of polynomial but there is no reason why we have to hard code the representation into the logic of the program so deeply. Besides, we are not the only ones who will want to know that this is a zero polynomial, so we should adopt the same approach we used with {\bf Term} and export a {\tt zero?} function. The signature looks like: \begin{small} \begin{verbatim} zero?: % -> Boolean; \end{verbatim} \end{small} (Notice again that we have the same signature as the {\tt zero?} from {\bf Term} but the {\tt \%} now refers to {\bf Polynomial}. It is vital that you know what {\tt \%} means at any given time. Indeed, the compiler spends a large amount of time deciding the same philosophical question.) Oh, by the way, we have another design decision to make (remember the universal law). Our polynomial representation allows {\em many} representations for the zero polynomial. Any list of zero coefficient terms is a zero polynomial. We could write a function to check this condition but it would be better to decide on a single representation of zero. This is known in the literature as a canonical representation. We can get such a representation if we enforce the rule that no polynomial has a zero coefficient for the highest exponent. If we generate a polynomial that has a zero coefficient as the highest exponent we shorten the polynomial representation until this is no longer true. Following this rule the zero polynomial is represented as a list of length 0. Canonical representations are important for deciding various questions such as equality or zero equivalence. Decisions about this issue and issues like sparse versus dense representations serve to distinguish one computer algebra system from another in fundamental ways. There are many tradeoffs but no one correct solution. So, we add the {\tt zero? poly} test early in the printing: \begin{small} \begin{verbatim} (stream: TextWriter) \<\< (poly: %): TextWriter == { zero? poly => stream \<\< 0; size: SingleInteger := #(rep(poly)); prefix: String := ""; for i in 1..(size-2) repeat if not zero?(poly.i) then { stream \<\< prefix \<\< poly.i \<\< "^" \<\< (size-i); prefix := " + " } if not zero?(poly.(size-1)) then { stream \<\< prefix \<\< poly.(size-1); prefix := " + " } if not zero?(poly.size) then stream \<\< prefix \<\< coef(poly.size); stream } \end{verbatim} \end{small} Still another problem. We print {\tt 1*x}. Normal mathematical notation elides the {\tt 1} and would just print {\tt x}. The best place to fix this is in {\bf Term}. Printing a term which has a {\bf coef} of {\bf 1} should just print the variable. One more problem, while we are at it. What happens if the term has a negative coefficient? Well we print something like: \begin{small} \begin{verbatim} -3*x^2 + -2*x + -1 \end{verbatim} \end{small} which is certainly correct but really ugly. Let's fix that with another pass. We need to be able to negate a term so that we can flip the sign of a negative term. So we add the signature: \begin{small} \begin{verbatim} -: % -> %; \end{verbatim} \end{small} to {\bf Term}. This is unary negation. We also need predicates that tell whether a term is positive or negative: \begin{small} \begin{verbatim} positive? % -> Boolean; negative? % -> Boolean; \end{verbatim} \end{small} We might as well add the ability to add and subtract terms while we are at it, since we will need them later when adding and subtracting polynomials. These signatures need to be added to {\bf Term}'s export list: \begin{small} \begin{verbatim} -:(%,%) -> %; +:(%,%) -> %; \end{verbatim} \end{small} Now, back to printing the polynomial with negative terms. Let's make two local functions: {\bf prefix}, which takes a term and returns the correct prefix string, and {\bf abs}, which takes a term and returns a term with a positive sign. Local functions are in the implementation section of the code but their signature is {\em not\/} in the exports list. Since {\bf prefix} and {\bf abs} are not in the export list of {\bf Polynomial} there is no way for anyone to know these functions exist. They are hidden in the {\bf Polynomial} box. They aren't particularly general or interesting, but make the code (slightly) clearer. \begin{small} \begin{verbatim} prefix(term: Term): String == if negative? term then " - " else " + "; abs(term: Term): Term == if negative? term then -term else term; (stream: TextWriter) \<\< (poly: %): TextWriter == { zero? poly => stream \<\< 0; size: SingleInteger := #(rep(poly)); prefix: String := if negative?(poly.1) then " - " else ""; for i in 1..(size-2) repeat if not zero?(poly.i) then { stream \<\< prefix \<\< abs(poly.i); stream \<\< "^" \<\< (size - i); prefix := prefix(poly.(i+1)) } if not zero?(poly.(size-1)) then { stream \<\< prefix \<\< abs(poly.(size-1)); prefix := prefix(poly.size) } if not zero?(poly.size) then stream \<\< prefix \<\< abs(coef(poly.size)); stream } \end{verbatim} \end{small} Remember: There is no such thing as a simple job. \subsection{Polynomial --- a return from printing} The accessor functions for a {\bf Polynomial} fall into several cases. We would like to be able to access the leading term of the polynomial and each term of the polynomial. A single term is referred to as a {\em monomial}. \begin{small} \begin{verbatim} leadingMonomial: % -> Term; apply: (%, SingleInteger) -> Term; \end{verbatim} \end{small} Notice that our representation of polynomials does not provide the exponent directly, so the user has to know what the exponent of a given term should be. In general, the $i$-th term from the polynomial will be {\bf $x^i$}. However, the user needs to know the highest exponent of the polynomial (referred to as the {\tt degree}): \begin{small} \begin{verbatim} degree: % -> SingleInteger; \end{verbatim} \end{small} This is good enough for a first try at a {\bf Polynomial} type. The next example is an implementation of this type. \subsection{Listing} \label{PolynomialListing} \begin{small} \begin{verbatim} #include "axllib" Term: BasicType with { new: (SingleInteger, Character) -> %; dispose!: % -> (); \<\<: (TextWriter, %) -> TextWriter; coef: % -> SingleInteger; var: % -> Character; zero?: % -> Boolean; positive?: % -> Boolean; negative?: % -> Boolean; -: % -> %; -:(%,%) -> %; +:(%,%) -> %; } == add { Rep == Record(coef: SingleInteger, var: Character); import from Rep; new(number: SingleInteger, variable: Character): % == per [number, variable]; dispose!(ignore: %):() == {} (stream: TextWriter) \<\< (term: %): TextWriter == if rep(term).coef = 1 then stream \<\< rep(term).var else { stream \<\< rep(term).coef; stream \<\< "*" \<\< rep(term).var } coef(term: %): SingleInteger == rep(term).coef; var(term: %): Character == rep(term).var; (term1: %) = (term2: %): Boolean == { coef term1 ~= coef term2 => false; var term1 ~= var term2 => false; true } sample: % == per [0, char "x"]; zero?(term: %): Boolean == coef(term) = 0; positive?(term: %): Boolean == coef(term) > 0; negative?(term: %): Boolean == coef(term) < 0; -(term: %): % == per [-coef(term), var term]; (term1: %) - (term2: %): % == { var term1 ~= var term2 => error "Subtracting terms with incompatible vars"; per [coef(term1) - coef(term2), var term1] } (term1: %) + (term2: %): % == { var term1 ~= var term2 => error "Adding terms with incompatible vars"; per [coef(term1) + coef(term2), var term1] } } Polynomial: with { new: List(Term) -> %; dispose!: % -> (); \<\<: (TextWriter, %) -> TextWriter; leadingMonomial: % -> Term; apply: (%, SingleInteger) -> Term; degree: % -> SingleInteger; zero?: % -> Boolean; } == add { import from List Term; import from SingleInteger; Rep == Array Term; import from Rep; new(terms: List Term): % == { size: SingleInteger := #terms; result: Rep := new(size, sample@Term); for i in 1..size repeat result.i:=terms.i; per result } dispose!(ignore: %):() == {} prefix(term: Term): String == if negative? term then " - " else " + "; abs(term: Term): Term == if negative? term then -term else term; (stream: TextWriter) \<\< (poly: %): TextWriter == { zero? poly => stream \<\< 0; size: SingleInteger := #(rep(poly)); sign: String := if negative?(poly.1) then " - " else ""; for i in 1..(size-2) repeat if not zero?(poly.i) then { stream \<\< sign \<\< abs(poly.i); stream \<\< "^" \<\< (size - i); sign := prefix(poly.(i + 1)) } if not zero?(poly.(size - 1)) then { stream \<\< sign \<\< abs(poly.(size-1)); sign := prefix(poly.size) } if not zero?(poly.size) then stream \<\< sign \<\< abs(coef(poly.size)); stream } leadingMonomial(poly: %): Term == rep(poly).(#(rep(poly))); apply(poly: %, exponent: SingleInteger): Term == rep(poly).exponent; degree(poly: %): SingleInteger == #(rep(poly)); zero?(poly: %): Boolean == #(rep(poly)) = 0; } #if TEST import from Character; import from SingleInteger; import from List Term; import from Polynomial; var: Character := char "x"; term1 := new(3, var); term2 := new(2, var); term3 := new(1, var); term4 := new(0, var); term5 := new(-3, var); -- term6 := -term5; print \<\< new(list(term5,term5,term5)) \<\< newline; -- negative signs print \<\< new(list(term3,term2,term1)) \<\< newline; -- 1 elision print \<\< new(list(term1,term2,term3)) \<\< newline; print \<\< new(list(term4,term2,term3)) \<\< newline; print \<\< new(list(term1,term4,term3)) \<\< newline; print \<\< new(list(term4,term4,term3)) \<\< newline; print \<\< new(list(term1,term2,term4)) \<\< newline; -- bad leading term print \<\< new(list(term4,term2,term4)) \<\< newline; -- bad leading term print \<\< new(list(term1,term4,term4)) \<\< newline; -- bad leading term print \<\< new(list(term4,term4,term4)) \<\< newline; -- bad leading term print \<\< new(list())@Polynomial \<\< newline; -- true zero polynomial #endif -- TEST \end{verbatim} \end{small} \section{Operations in the Type ``Polynomial''} {\bf The complete listing for this section is at page \pageref{OpsInPolynomialListing}.} {\bf Polynomial}s are interesting objects and one can define several dozen interesting operations on objects of this {\bf Type}. We introduce two just to give you the details of how to do it. The two operations are addition ({\tt +}) and subtraction ({\tt -}). These are infix operations. Their signatures look like: \begin{small} \begin{verbatim} +: (%,%) -> %; -: (%,%) -> %; \end{verbatim} \end{small} That is, they take two objects, both of the current {\bf Type} (in this % "Both" added to avoid bad linebreak. case, {\bf Polynomial}), and return an object of the same {\bf Type}. The implementations are fairly straightforward. Remember that each polynomial is just an array of terms and that the position in the array defines the exponent of the term. Since this is the case, in principle we only need to create an array of the right target length and loop over each element pair, adding or subtracting them. A slight complication is that the arrays may be of different lengths: we overcome this by choosing the greater length for the final array, and taking the sum or difference only for terms which exist in both polynomials. \begin{small} \begin{verbatim} (poly1: %) + (poly2: %): % == { zero? poly1 => poly2; zero? poly2 => poly1; if (l1: SingleInteger := #(rep(poly1))) < (l2: SingleInteger := #(rep(poly2))) then { result: Rep := new(l2, sample@Term); d: SingleInteger := l2 - l1; for i in 1..d repeat result.i := poly2.i; for i in (d + 1)..l2 repeat result.i := poly1.(i - d) + poly2.i } else { result: Rep := new(l1, sample@Term); d: SingleInteger := l1 - l2; for i in 1..d repeat result.i := poly1.i; for i in (d + 1)..l1 repeat result.i:=poly2.(i - d) + poly1.i } per result } (poly1: %) - (poly2: %): % == { zero? poly1 => poly2; zero? poly2 => poly1; if (l1: SingleInteger := #(rep(poly1))) < (l2: SingleInteger := #(rep(poly2))) then { result: Rep := new(l2, sample@Term); d: SingleInteger := l2 - l1; for i in 1..d repeat result.i := - poly2.i; for i in (d + 1)..l2 repeat result.i:=poly1.(i - d) - poly2.i } else { result: Rep := new(l1, sample@Term); d: SingleInteger := l1 - l2; for i in 1..d repeat result.i := poly1.i; for i in (d + 1)..l1 repeat result.i:=poly2.(i - d) - poly1.i } per result } \end{verbatim} \end{small} This is not strictly correct, however, since the subtraction can generate terms which are zero at the highest powers of the polynomial. We should reduce the length of the polynomial to elide these terms. Now we begin a series of tests for the various cases of creating and printing polynomials. First we need to bring the domains we will use into scope. \begin{small} \begin{verbatim} import from Character; import from SingleInteger; import from List Term; import from Polynomial; \end{verbatim} \end{small} Since polynomials are lists of terms we create a few terms in the variable {\tt x}, which we can use to construct polynomials. \begin{small} \begin{verbatim} var: Character := char "x"; term1 := new(3, var); term2 := new(2, var); term3 := new(1, var); term4 := new(0, var); term5 := new(-3, var); -- term6 := -term5; \end{verbatim} \end{small} We need to check the handling of leading negative signs: \begin{small} \begin{verbatim} print \<\< new(list(term5,term5,term5)) \<\< newline; -- negative signs \end{verbatim} \end{small} We need to check that we print {\tt 1*x} as {\tt x}. \begin{small} \begin{verbatim} print \<\< new(list(term3,term2,term1)) \<\< newline; -- 1 elision \end{verbatim} \end{small} We need to check that {\tt 0*x} is skipped properly: \begin{small} \begin{verbatim} print \<\< new(list(term1,term2,term3)) \<\< newline; print \<\< new(list(term4,term2,term3)) \<\< newline; print \<\< new(list(term1,term4,term3)) \<\< newline; print \<\< new(list(term4,term4,term3)) \<\< newline; print \<\< new(list(term1,term2,term4)) \<\< newline; -- bad leading term print \<\< new(list(term4,term2,term4)) \<\< newline; -- bad leading term print \<\< new(list(term1,term4,term4)) \<\< newline; -- bad leading term print \<\< new(list(term4,term4,term4)) \<\< newline; -- bad leading term \end{verbatim} \end{small} We need to check that we print the zero polynomial properly: \begin{small} \begin{verbatim} print \<\< new(list())@Polynomial \<\< newline; -- true zero polynomial print \<\< 0@Polynomial \<\< newline; -- true zero polynomial \end{verbatim} \end{small} We need to check that term arithmetic is properly implemented: \begin{small} \begin{verbatim} print \<\< term1 + term2 \<\< newline; print \<\< term1 - term2 \<\< newline; print \<\< term2 - term1 \<\< newline; print \<\< term1 - term1 \<\< newline; \end{verbatim} \end{small} %#endif --example5 \subsection{Listing} \label{OpsInPolynomialListing} \begin{small} \begin{verbatim} #include "axllib" Term: BasicType with { new: (SingleInteger, Character) -> %; dispose!: % -> (); \<\<: (TextWriter, %) -> TextWriter; coef: % -> SingleInteger; var: % -> Character; zero?: % -> Boolean; positive?: % -> Boolean; negative?: % -> Boolean; -: % -> %; -:(%,%) -> %; +:(%,%) -> %; } == add { Rep == Record(coef: SingleInteger, var: Character); import from Rep; new(number: SingleInteger, variable: Character): % == per [number, variable]; dispose!(ignore: %):() == {} (stream: TextWriter) \<\< (term: %): TextWriter == if rep(term).coef = 1 then stream \<\< rep(term).var else { stream \<\< rep(term).coef; stream \<\< "*" \<\< rep(term).var } coef(term: %): SingleInteger == rep(term).coef; var(term: %): Character == rep(term).var; (term1: %) = (term2: %): Boolean == { coef term1 ~= coef term2 => false; var term1 ~= var term2 => false; true } sample: % == per [0, char "x"]; zero?(term: %): Boolean == coef(term) = 0; positive?(term: %): Boolean == coef(term) > 0; negative?(term: %): Boolean == coef(term) < 0; -(term: %): % == per [-coef(term), var term]; (term1: %) - (term2: %): % == { var term1 ~= var term2 => error "Term: Variables do not match"; per [coef term1 - coef term2, var term1] } (term1): % + (term2: %): % == { var term1 ~= var term2 => error "Term: Variables do not match"; per [coef term1 + coef term2, var term1] } } Polynomial: with { new: List(Term) -> %; dispose!: % -> (); \<\<: (TextWriter, %) -> TextWriter; leadingMonomial: % -> Term; apply: (%, SingleInteger) -> Term; degree: % -> SingleInteger; 0: %; zero?: % -> Boolean; +: (%,%) -> %; -: (%,%) -> %; } == add { import from List Term; import from SingleInteger; Rep == Array Term; import from Rep; new(terms: List Term): % == { size: SingleInteger := #terms; result: Rep := new(size, sample@Term); for i in 1..size repeat result.i := terms.i; per(result) } dispose!(ignore: %):() == {} -- undefined prefix(term: Term): String == if negative? term then " - " else " + "; abs(term: Term): Term == if negative? term then -term else term; (stream: TextWriter) \<\< (poly: %): TextWriter == { zero? poly => stream \<\< 0@%; size: SingleInteger := #(rep(poly)); sign: String:= if negative? (poly.1) then " - " else ""; for i in 1..(size - 2) repeat if not zero?(poly.i) then { stream \<\< sign \<\< abs(poly.i); stream \<\< "^" \<\< (size - i); sign := prefix(poly.(i+1)) } if not zero?(poly.(size-1)) then { stream \<\< sign \<\< abs(poly.(size-1)); sign := prefix(poly.size) } if not zero?(poly.size) then stream \<\< sign \<\< abs(coef(poly.size)); stream } leadingMonomial(poly: %): Term == rep(poly).(#(rep(poly))); apply(poly: %, exponent: SingleInteger): Term == rep(poly).exponent; degree(poly: %): SingleInteger == #(rep(poly)); 0: % == new(list())@Polynomial; zero?(poly: %): Boolean == #(rep(poly)) = 0; (poly1: %) + (poly2: %): % == { zero? poly1 => poly2; zero? poly2 => poly1; if (l1: SingleInteger := #(rep(poly1))) < (l2: SingleInteger := #(rep(poly2))) then { result: Rep := new(l2, sample@Term); d: SingleInteger := l2 - l1; for i in 1..d repeat result.i := poly2.i; for i in (d + 1)..l2 repeat result.i := poly1.(i - d) + poly2.i } else { result: Rep := new(l1, sample@Term); d: SingleInteger := l1 - l2; for i in 1..d repeat result.i := poly1.i; for i in (d + 1)..l1 repeat result.i:=poly2.(i - d) + poly1.i } per result } (poly1: %) - (poly2: %): % == { zero? poly1 => poly2; zero? poly2 => poly1; if (l1: SingleInteger := #(rep(poly1))) < (l2: SingleInteger := #(rep(poly2))) then { result: Rep := new(l2, sample@Term); d: SingleInteger := l2 - l1; for i in 1..d repeat result.i := - poly2.i; for i in (d + 1)..l2 repeat result.i:=poly1.(i - d) - poly2.i } else { result: Rep := new(l1, sample@Term); d: SingleInteger := l1 - l2; for i in 1..d repeat result.i := poly1.i; for i in (d + 1)..l1 repeat result.i:=poly2.(i - d) - poly1.i } per result } } \end{verbatim} \end{small} \section{Parameterized types} {\bf The complete listing for this section is at page \pageref{ParamTypesListing}.} Types can be more general than we have seen so far. One generalization is to allow the types to take parameters. That is, we can construct a type which will change its behavior depending on some other type. If we look at general polynomials, we find that there are several different types of coefficients. We could have polynomials of the form: \begin{small} \begin{verbatim} 3*x^2 + 2*x + 1 or 3.0*x^2 + 2.0*x + 1.0 or (3/5)*x^2 + (2/5)*x + (1/5) \end{verbatim} \end{small} The first polynomial has integer coefficients. The second has real coefficients and the third has rational (ratios of integers) coefficients. The type of number allowed in the coefficient of a polynomial is determined by the ring of coefficients. Rings are simple mathematical objects that define operations like addition and subtraction. Since polynomials depend on the terms to define what it means to add or subtract something, we find that polynomials change their behavior depending on the ring of coefficients chosen. We could implement this by defining ``integer'' polynomials, ``real'' polynomials and ``rational'' polynomials as separate types. However, most of the operations we want are common to all of these polynomial types. What we would like to be able to do is define {\bf Polynomial}s that take different kinds of {\bf Term}s. The same argument applies for {\bf Term}s. Rather than having many different kinds of {\bf Term}s, we can change {\bf Term} to take a parameter that defines the kind of coefficients to use. Let's start this whole process by modifying {\bf Term} to take a parameter which tells us the {\bf Type} of a coefficient. The previous {\bf Type} definition line for {\bf Term} was: \begin{small} \begin{verbatim} Term: BasicType with { \end{verbatim} \end{small} which has been changed to: \begin{small} \begin{verbatim} Term(CoefType: OrderedRing): BasicType with { \end{verbatim} \end{small} There is much to say about this change. The first and most notable difference is that {\bf Term} is no longer a constant {\bf Type}. It is now a function that takes an argument. We have given a name to the argument and, as in all of our function definitions, given the {\bf Type} of the argument. One question that arises is how and why we chose the type {\bf OrderedRing}. When we build {\bf Type} towers we depend on the things under us in the tower to supply certain operations. If we build on something that does not supply the needed operations then we have no meaning for our program (what would it mean to add two things of {\bf Type} {\tt Display}, for example). A reasonable initial guess for a declaration line might be: \begin{small} \begin{verbatim} Term(CoefType: BasicType): BasicType with { \end{verbatim} \end{small} but this fails, because the code that follows assumes that we can compare the coefficient to the constant {\bf 1}. However, things that are {\bf BasicType}s only have the operations: ({\tt =}, {\tt \~{}=}, %{\tt $\<\<$}, {\tt sample}, {\tt hash}) and are not required to have ``{\bf \<\<}, {\tt sample}, {\tt hash}) and are not required to have the constant {\bf 1}. The guarantee that a {\bf Type} has the constant {\bf 1} first appears in the (very primitive) type {\bf Monoid} (see \ref{axlcatFigure} on pageref{axlcatFigure}). So we could satisfy this requirement with the definition line: \begin{small} \begin{verbatim} Term(CoefType: Monoid): BasicType with { \end{verbatim} \end{small} Again we run into a problem: some of the operations we have implemented in {\bf Term} (like {\tt positive?}) require us to use the {\tt >} operation to compare two coefficients. Being able to compare two things to decide if one is greater implies that there is an order. Pigments, for example, are not ordered. So we need to go further into the {\bf Type} hierarchy to find something that is both a {\bf Monoid} and has {\bf Order}. The required {\bf Type} is {\bf OrderedRing}. So, in order (intentional pun) to {\em guarantee} that we will be able to compare coefficients for equality to {\bf 1} and compare two coefficients to decide which is larger, we have to give {\bf Term} something that is at least an {\bf OrderedRing}. This gives us the required function definition line: \begin{small} \begin{verbatim} Term(CoefType: OrderedRing): BasicType with { \end{verbatim} \end{small} We originally wrote the {\tt Rep} so that it assumed that the {\tt coef} field of the {\bf Record} (which is how we store {\bf Term}s internally) would be of {\bf Type} {\tt SingleInteger}. We must change this. The old {\tt Rep} read: \begin{small} \begin{verbatim} Rep == Record(coef: SingleInteger, var: Character); \end{verbatim} \end{small} and now it reads: \begin{small} \begin{verbatim} Rep == Record(coef: CoefType, var: Character); \end{verbatim} \end{small} This tells us that we can store anything that satisfies our {\tt CoefType} requirement in the internal representation. The next change we need to make is in the signature lines of certain functions. The old signature for the function {\tt new} was: \begin{small} \begin{verbatim} new: (SingleInteger, Character) -> %; \end{verbatim} \end{small} which has been changed to: \begin{small} \begin{verbatim} new: (CoefType, Character) -> %; \end{verbatim} \end{small} so that we used to require a {\bf SingleInteger} as the coefficient and now we can have any coefficient that is of type {\bf CoefType}. This can be anything, as long as it is {\em at least} an {\bf OrderedRing}. Since we changed the function signature we must make the corresponding change in the function header line. It used to read: \begin{small} \begin{verbatim} new(number: SingleInteger, variable: Character): % == \end{verbatim} \end{small} and now it reads: \begin{small} \begin{verbatim} new(number: CoefType, variable: Character): % == \end{verbatim} \end{small} Similarly, we assumed that {\tt coef} would return a {\bf SingleInteger}: \begin{small} \begin{verbatim} coef: % -> SingleInteger; coef: % -> CoefType; \end{verbatim} \end{small} and now it returns anything that is stored in the {\bf Term}. Since we changed the function signature we must make the corresponding change in the function header line. It used to read: \begin{small} \begin{verbatim} coef(term: %): SingleInteger == \end{verbatim} \end{small} and now it reads: \begin{small} \begin{verbatim} coef(term: %): CoefType == \end{verbatim} \end{small} \subsection{Listing} \label{ParamTypesListing} \begin{small} \begin{verbatim} #include "axllib" Term(CoefType: OrderedRing): BasicType with { new: (CoefType, Character) -> %; dispose!: % -> (); \<\<: (TextWriter, %) -> TextWriter; coef: % -> CoefType; var: % -> Character; zero?: % -> Boolean; positive?: % -> Boolean; negative?: % -> Boolean; -: % -> %; -:(%,%) -> %; +:(%,%) -> %; } == add { Rep == Record(coef: CoefType, var: Character); import from Rep; new(number: CoefType, variable: Character): % == per [number,variable]; dispose!(ignore: %):() == {} -- undefined (stream: TextWriter) \<\< (term: %): TextWriter == if rep(term).coef = 1 then stream \<\< rep(term).var else { stream \<\< rep(term).coef; stream \<\< "*" \<\< rep(term).var } coef(term: %): CoefType == rep(term).coef; var(term: %): Character == rep(term).var; (term1: %) = (term2: %): Boolean == { coef(term1) ~= coef(term2) => false; var(term1) ~= var(term2) => false; true } sample: % == per [0, char "x"]; zero?(term: %): Boolean == coef(term) = 0; positive?(term: %): Boolean == coef(term) > 0; negative?(term: %): Boolean == coef(term) < 0; -(term: %): % == per [-coef(term), var term]; (term1: %) - (term2: %): % == { var term1 ~= var term2 => error "Term: Variables do not match"; per [coef(term1)-coef(term2), var term1] } (term1: %) + (term2: %): % == { var term1 ~= var term2 => error "Term: Variables do not match"; per [coef(term1)+coef(term2), var term1] } } #if TEST import from Character; import from Term SingleInteger; print \<\< new(0$SingleInteger,char "x") \<\< newline; import from Term Float; print \<\< new(0$Float,char "x") \<\< newline; #endif -- TEST \end{verbatim} \end{small} Many thanks to the reviewers: Peter Broadbery, Robert Corless, George Corliss, Tim Daly, Jr., Pietro Iglio, Phillip Santas, Jon Steinbach and Stephen Watt. At this point you know enough to write reasonably functional Axiom programs. We have introduced the concept of a domain as a means of structuring Axiom programs. We have shown examples of domains and explored the various parts, namely the export list, the representation and the implementation. We have shown how to connect the domain to the existing type hierarchy. \eject \begin{thebibliography}{99} \bibitem{1} nothing \end{thebibliography} \end{document}