\tracingmacros=3 % Document Type: LaTeX % Master File: meyer-ps5.tex %\input /zu/6001-devel/6001mac \input ../6001mac \newcommand{\Code}[1]{\mbox{\tt #1}} \outer\def\beginlispbig{% \begin{minipage}[t]{\linewidth} \begin{list}{$\bullet$}{% \setlength{\topsep}{0in} \setlength{\partopsep}{0in} \setlength{\itemsep}{0in} \setlength{\parsep}{0in} \setlength{\leftmargin}{1.5em} \setlength{\rightmargin}{0in} \setlength{\itemindent}{0in} }\item[] \obeyspaces \obeylines \tt} \def\fbox#1{% \vtop{\vbox{\hrule% \hbox{\vrule\kern3pt% \vtop{\vbox{\kern3pt#1}\kern3pt}% \kern3pt\vrule}}% \hrule}} \let\to\rightarrow \let\union\cup \let\cross\times \def\SI{\mbox{Sch-\-Int}} \def\SNat{\mbox{Sch-\-NatNum}} %\def\SNI{\mbox{Sch-\-Nonneg-\-Int}} \def\SN{\mbox{Sch-\-Num}} \def\SB{\mbox{Sch-\-Bool}} \def\Empty{\mbox{Empty}} \def\SI{\mbox{Sch-\-Int}} \def\SSYM{\mbox{Sch-\-Symbol}} \def\GN{\mbox{Generic-\-Num}} \def\RN{\mbox{RepNum}} \def\RR{\mbox{RepRat}} \def\RP{\mbox{RepPoly}} \def\RT{\mbox{RepTerm}} \def\RTS{\mbox{RepTerms}} \def\TL{\List(\RT)} \def\Var{\mbox{Variable}} \def\RP{\mbox{RepPoly}} \def\Empty{\mbox{Empty-type}} \def\List{\mbox{List}} % \def\nill{\mbox{nil}} \def\GOP2{\mbox{Gen-binary-op}} \def\numtag{\Code{number}} \def\rattag{\Code{rational}} \def\polytag{\Code{polynomial}} \begin{document} \psetheader{Sample Problem Set}{Math Set} \begin{center}\large {\bf A Generic Arithmetic Package} \end{center} \medskip \noindent This problem set is based on Sections 2.5 and 2.6 of the notes, which discuss a generic arithmetic system that is capable of dealing with rational functions (quotients of polynomials). You should study and understand these sections and also carefully read and think about this handout before attempting to solve the assigned problems. There is a larger amount of code for you to manage in this problem set than in previous ones. Furthermore, the code makes heavy use of data-directed techniques. We do not intend for you to study it all---and you may run out of time if you try. This problem set will give you an opportunity to acquire a key professional skill: mastering the code {\em organization} well enough to know what you need to understand and what you don't need to understand. Be aware that in a few places, which will be explicitly noted below, this problem set modifies (for the better!) the organization of the generic arithmetic system described in the text. \section{Generic Arithmetic} The generic arithmetic system consists of a number of pieces. The complete code is attached at the end of the handout. All of this code will be loaded into Scheme when you load the files for this problem set. You will not need to edit any of it. Instead you will augment the system by adding procedures and installing them in the system. Hand in your PreLab work, computer listings of all the procedures you write in lab, and transcripts showing that the required functionality was added to the system. The transcript should include enough tests to exercise the functionality of your modifications and to demonstrate that they work properly. \subsection{The basic generic arithmetic system} There are three kinds, or {\em subtypes}, of generic numbers in the system of this Problem Set: generic ordinary numbers, generic rational numbers, and generic polynomials. Elements of these subtypes are tagged items with one of the tags \numtag, \rattag, or \polytag, followed by a data structure representing an element of the corresponding subtype. For example, a generic ordinary number has tag \numtag\ and another part, called its {\em contents}, which represents an ordinary number. We can summarize this in a type equation: \[\GN = (\{\numtag\}\cross \RN) \union (\{\rattag\}\cross \RR) \union (\{\polytag\}\cross \RP).\] The type tagging mechanism is the simple one described on p.\ 165 of the text, and the \Code{apply-generic} is the one {\em without coercions} described in section 2.5.3. The code for these is in \Code{types.scm}. We will also assume that the commands {\tt put} and {\tt get} are available to automagically update the table of methods around which the system is designed. You needn't be concerned in this problem set how {\tt put} and {\tt get} are implemented\footnote{This will be explained when we come to section 3.3.3 of the Notes.}. Some familiar arithmetic operations on generic numbers are \beginlisp (define (add x y) (apply-generic 'add x y)) (define (sub x y) (apply-generic 'sub x y)) (define (mul x y) (apply-generic 'mul x y)) (define (div x y) (apply-generic 'div x y)) \endlisp These are all of type $(\GN,\GN) \to \GN$. We also have \beginlisp (define (negate x) (apply-generic 'negate x)) \endlisp of type $\GN \to \GN$, and \beginlisp (define (=zero? x) (apply-generic '=zero? x)) \endlisp of type $\GN \to \SB$. Using these operations, compound generic operations can be defined, such as \beginlisp (define (square x) (mul x x)) \endlisp \subsection{Packages} The code for the generic number system of this problem set has been organized in \Code{ps5-code.scm} into groups of related definitions labelled as ``packages.'' A package generally consists of all the procedures for handling a particular type of data, or for handling the interface between packages. The packages described in the text are enclosed in a package installation procedure that sets up internal definitions of the procedures in the package. An example is \Code{the-number-package} on p.\ 178. This ensures there will be no conflict if a procedure with the same name is used in another package, allowing packages to be developed separately with minimal coordination of naming conventions. In this assignment it will be more convenient {\em not} to enclose the packages into internal definitions. Instead, the code is laid out textually in packages, but essentially everything is defined at ``top level.'' You will see that we have therefore been careful to choose different names for corresponding procedures in different packages, e.g., \Code{+} which adds in the number package and \Code{+poly} which adds in the polynomial package. \subsection{Ordinary numbers} To install ordinary numbers, we must first decide how they are to be represented. Since Scheme already has an elaborate system for handling numbers, the most straightforward thing to do is to use it, namely, let \[\RN = \SN.\] This allows us to define the methods that handle generic ordinary numbers simply by calling the Scheme primitives \Code{+}, \Code{-}, \ldots, as in section 2.6.1. So we can immediately define interface procedures between \RN's and the Generic Number System: \beginlisp (define (+number x y) (make-number (+ x y))) (define (-number x y) (make-number (- x y))) (define (*number x y) (make-number (* x y))) (define (/number x y) (make-number (/ x y))) \endlisp These are of type $(\RN, \RN) \to (\{\numtag\}\cross\RN)$. Also, \beginlisp (define (negate-number x) (make-number (- x))) \endlisp of type $\RN \to (\{\numtag\}\cross\RN)$, \beginlisp (define (=zero-number? x) (= x 0)) \endlisp of type $\RN \to \SB$, and \beginlisp (define (make-number x) (attach-tag 'number x)) \endlisp of type $\RN \to (\{\numtag\}\cross\RN)$. All but the last of these procedures get installed in the table as methods for handling generic ordinary numbers: \beginlisp (put 'add '(number number) +number) (put 'sub '(number number) -number) (put 'mul '(number number) *number) (put 'div '(number number) /number) (put 'negate '(number) negate-number) (put '=zero? '(number) =zero-number?) \endlisp The number package should provide a means for a user to create generic ordinary numbers, so we include a user-interface procedure\footnote{In Exercise 2.76 in the text, the implementation of the type tagging system is modified to maintain the illlusion that generic ordinary numbers have a \numtag\ tag, without actually attaching the tag to Scheme numbers. This implementation has the advantage that generic ordinary numbers are represented exactly by Scheme numbers, so there is no need to provide the user-interface procedure \Code{create-number}. Note that in Section 6 following Exercise 2.76, the text implicitly assumes that this revised implementation of tags has been installed. In this problem set we stick to the straightforward implementation with actual \numtag\ tags.} of type $\SN \to (\{\numtag\}\cross\RN)$, namely, \beginlisp (define (create-number x) (attach-tag 'number x)) \endlisp \paragraph{Exercise 5.1A} The generic equality predicate \[\Code{equ?}:(\GN,\GN) \to \SB\] is supposed to test equality of its arguments. Define an \Code{=number} procedure in the Number Package suitable for installation as a method allowing generic \Code{equ?} to handle generic ordinary numbers. Include the type of \Code{=number} in comments accompanying your definition. \paragraph{Lab exercise 5.1B} Install {\tt equ?} as an operator on numbers in the generic arithmetic package. Test that it works properly on generic ordinary numbers. \subsection{Rational numbers} The second piece of the system is a Rational Number package like the one described in section 2.1.1. The difference is that the arithmetic operations used to combine numerators and denominators are {\em generic} operations, rather than the primitive {\tt +}, {\tt -}, etc. This difference is important, because it allows ``rationals'' whose numerators and denominators are arbitrary generic numbers, rather than only integers or ordinary numbers. The situation is like that in Section 2.6.3 in which the use of generic operations in {\tt +terms} and {\tt *terms} allowed manipulation of polynomials with arbitrary coefficients. We begin by specifying the representation of rationals as {\em pairs} of \GN's: \[\RR = \GN\cross\GN\] with constructor \beginlisp (define (make-rat numerator denominator) (cons numerator denominator)) \endlisp of type $\GN, \GN \to \RR$, and selectors \beginlisp (define numer car) (define denom cdr) \endlisp Note that {\tt make-rat} does not reduce rationals to lowest terms as in Section 2.1.1, because {\tt gcd} makes sense only in certain cases---such as when numerator and denominator are integers---but we are allowing arbitrary numerators and denominators. Now we define basic procedures of type $(\RR, \RR) \to \RR$ within the Rational Number package: \beginlisp (define (+rat x y) (make-rat (add (mul (numer x) (denom y)) (mul (denom x) (numer y))) (mul (denom x) (denom y)))) (define (-rat x y) (make-rat (sub (mul (numer x) (denom y)) (mul (denom x) (numer y))) (mul (denom x) (denom y)))) (define (*rat x y) (make-rat (mul (numer x) (numer y)) (mul (denom x) (denom y)))) (define (/rat x y) (make-rat (mul (numer x) (denom y)) (mul (denom x) (numer y)))) \endlisp There is also \beginlisp (define (negate-rat x) (make-rat (negate (numer x)) (denom x))) \endlisp of type $\RR \to \RR$, \beginlisp (define (=zero-rat? x) (=zero? (numer x))) \endlisp of type $\RR \to \SB$, and finally, \beginlisp (define (make-rational x) (attach-tag 'rational x)) \endlisp of type $\RR \to (\{\rattag\}\cross\RR)$. Next, we provide the interface between the Rational package and the Generic Number System, namely the methods for handling rationals. \beginlisp (define (+rational x y) (make-rational (+rat x y))) (define (-rational x y) (make-rational (-rat x y))) (define (*rational x y) (make-rational (*rat x y))) (define (/rational x y) (make-rational (/rat x y))) \endlisp of type $(\RR, \RR) \to (\{\rattag\}\cross\RR)$, \beginlisp (define (negate-rational x) (make-rational (negate-rat x))) \endlisp of type $\RR \to (\{\rattag\}\cross\RR)$, and \beginlisp (define (=zero-rational? x) (=zero-rat? x)) \endlisp of type $\RR \to \SB$. To install the rational methods in the generic operations table, we evaluate \beginlisp (put 'add '(rational rational) +rational) (put 'sub '(rational rational) -rational) (put 'mul '(rational rational) *rational) (put 'div '(rational rational) /rational) (put 'negate '(rational) negate-rational) (put '=zero? '(rational) =zero-rational?) \endlisp The Rational Package should also provide a means for a user to create Generic Rationals, so we include an external procedure of type $(\GN,\GN) \to (\{\rattag\}\cross\RR)$, namely, \beginlisp (define (create-rational x y) (make-rational (make-rat x y))) \endlisp \paragraph{Exercise 5.2} Produce expressions that define {\tt r5/13} to be the rational number $5/13$ and {\tt r2} to be the rational number $2/1$. Assume that the expression \beginlisp (define rsq (square (add r5/13 r2))) \endlisp is evaluated. Draw a box and pointer diagram that represents {\tt rsq}. \paragraph{Exercise 5.3A} Define a predicate {\tt equ-rat?} inside the Rational package that tests whether two rationals are equal. What is its type? \paragraph{Exercise 5.3B} Install the relevant method in the generic arithmetic package so that {\tt equ?} tests the equality of two generic rational numbers as well as two generic ordinary numbers. Test that {\tt equ?} works properly on both subtypes of generic numbers. \paragraph{Operations across Different Types} At this point all the methods installed in our system require all operands to have the subtype---all \numtag, or all \rattag. There are no methods installed for operations combining operands with distinct subtypes. For example, \beginlisp (define n2 (create-number 2)) (equ? n2 r2) \endlisp will return a ``no method'' error message because there is no equality method at the subtypes (\numtag\ \rattag). We have not built into the system any connection between the number 2 and the rational $2/1$. Some operations across distinct subtypes are straightforward. For example, to combine a rational with a number, $n$, coerce $n$ into the rational $n/1$ and combine them as rationals. \paragraph{Exercise 5.4A} Define a procedure \[\Code{repnum->reprat}: \RN \to \RR\] which coerces $n$ into $n/1$. Now, for any type, $T$, you can obtain a \[(\RN,\RR) \to T\] method from a \[(\RR,\RR) \to T\] method by applying the procedure \Code{RRmethod->NRmethod}: \beginlisp (define (RRmethod->NRmethod method) (lambda (num rat) (method (repnum->reprat num) rat))) \endlisp Use \Code{RRmethod->NRmethod} to define methods for generic \Code{add}, \Code{sub}, \Code{mul}, and \Code{div} at argument types (\numtag\ \rattag). Define methods for these operations at argument types (\rattag\ \numtag). Also define \Code{equ?} these argument types. \paragraph{Exercise 5.4B} Install your new methods. Test them on \Code{(equ?\ n2 r2)} and \[\Code{(equ?\ (sub (add n2 r5/13) r5/13) n2)}\] \subsection{Polynomials} The Polynomial package defines methods for handling generic polynomials which are installed by \beginlisp (put 'add '(polynomial polynomial) +polynomial) (put 'mul '(polynomial polynomial) *polynomial) (put '=zero? '(polynomial) =zero-polynomial?) \endlisp The package also includes an external procedure so the user can construct generic polynomials. Namely, \[\Code{create-polynomial}: (\Var, \List(\GN)) \to (\{\polytag\}\cross \RP)\] constructs generic polynomials from a variable and the list of coefficients starting at the high order term (this is the preferred representation for {\em dense} polynomials described in Section 2.6.3). Within the Polynomial package, polynomials are represented by {\em abstract} term lists, using the list format preferred for {\em sparse} polynomials as described in Section 2.6.3. These abstract term lists are not necessarily Scheme lists, but have their own constructors and selectors. (They are, in fact, implemented as ordinary lists in \Code{ps5-code.scm}, but the abstraction makes it easier to change to a possibly more efficient term list representation without changing code outside the Term List package.) So we have the type equations \begin{eqnarray*} \RP & = & \Var\cross\RTS\\ \RTS & = & \mbox{Empty-Term-List} \union (\RT \cross \RTS)\\ \RT & = & \SNat \cross \GN \end{eqnarray*} with term list constructors \begin{eqnarray*} \Code{the-empty-termlist} &:& \Empty \to \RTS\\ \Code{adjoin-term} &:& (\RT, \RTS) \to \RTS, \end{eqnarray*} and selectors \Code{first-term} and \Code{rest-terms}\footnote{The \Empty\ has no elements. The type statement \[\Code{make-an-element} : \Empty \to T\] indicates that the procedure \Code{make-an-element} take no arguments, and evaluating \Code{(make-an-element)} returns a value of type $T$. Such procedures are sometimes called ``thunks.'' There wasn't any special need to use a thunk as constructor for empty term lists---a constant equal to the empty term list would have served as well (better? \Code{:-)})---but it serves as a reminder that term lists are created differently than Scheme's lists.}. In this problem set, we do modify the definition of \Code{*-term-by-all-terms} given on p.\ 193 of the test. The new definition is: \beginlisp (define (*-term-by-all-terms t1 tlist) (map-terms (lambda (term) (*term t1 term)) tlist)) \null (define (*term t1 t2) (make-term (+ (order t1) (order t2)) (mul (coeff t1) (coeff t2)))) \endlisp \paragraph{Exercise 5.5A} What is the type of the procedure \Code{map-terms}? Supply its definition. \paragraph{Exercise 5.5B} Define a procedure \Code{create-numerical-polynomial} which, given a variable name, \Code{x}, and list of \SN, returns a generic polynomial in \Code{x} with the list as its coefficients. Use \Code{create-numerical-polynomial} to define \Code{p1} to be the generic polynomial \[p_1(x) = x^3 + 5x^2 + -2.\] \paragraph{Exercise 5.5C} Evaluate your definition of \Code{map-terms}, thereby completing the definition of multiplication of generic polynomials. Use the generic {\tt square} operator to compute the square of \Code{p1}, and the square of its square. Turn in the the {\bf pretty-printed} results of the squarings, as computed in lab. \medskip There are still few methods installed which work with operands of mixed types. This means that generic arithmetic on polynomials with generic coefficients of different types is likely to fail. For example, a representation of the polynomial $p_{2}(z,x) = p_{1}(x)z^{2} + 3z + 5$ is defined in buffer \Code{ps5-ans.scm} as: \beginlisp (define p2-mixed (create-polynomial 'z (list p1 (create-number 3) (create-number 5)))) \endlisp Now squaring \Code{p2-mixed} will generate a ``no method'' error message, because there is no method for multiplying the numerical coefficients 3 and 5 by the polynomial coefficient \Code{p1}. A definition which will work better in our system would be to replace 3 and 5 by the corresponding constant polynomials in \Code{x}: \beginlisp (define p2 (create-polynomial 'z (list p1 (create-polynomial 'x (list (create-number 3)) (create-polynomial 'x (list (create-number 5))))))) \endlisp \paragraph{Exercise 5.6A} Use \Code{create-rational} and \Code{create-numerical-polynomial} to define the following rationals whose numerators and denominators are polynomials in \Code{y}: \[3/y,\ (y^{2}+1)/y,\ 1/(y + -1),\ 2\] Then define a useful representation for $p_3(x,y)=(3/y)x^4 + ((y^{2}+1)/y)x^2 + (1/(y + -1))x + 2$. \paragraph{Exercise 5.6B} Use the generic {\tt square} operator to compute the square of \Code{p2} and \Code{p3}, and the square of the square of \Code{p2}. Turn in the definitions you typed to create \Code{p3} and the {\bf pretty-printed} results of the squarings, as computed in lab. \subsection{Completing the polynomial package} If you construct a chart of the dispatch table we have been building, you will see that there are some unfilled slots dealing with polynomials. Notably, the generic {\tt negate} and {\tt sub} operations do not know how to handle polynomials. (There is also no method for polynomial {\tt div}, but this is more problematical since polynomials are not closed under division, e.g., dividing $x+1$ by $x^2$ yields a {\em rational function} \[\frac{x+1}{x^2}\] which is not equivalent to any polynomial.) \paragraph{Exercise 5.7A} Use the procedure \Code{map-terms} to write a procedure \Code{negate-terms} that negates all the terms of a term list. Then use \Code{negate-terms} to define a procedure \Code{negate-poly}, and a method \Code{negate-polynomial}. Include the types in the comments accompanying your code. \paragraph{Exercise 5.7B} Using the {\tt negate-poly} procedure you created in exercise 5.7A, and the procedure {\tt +poly}, implement a polynomial subtraction procedure {\tt -poly}, and a method {\tt -polynomial}. Use {\tt -poly} and \Code{=zero-poly?} to implement \Code{equ-poly?} and \Code{equ-polynomial?} \paragraph{Exercise 5.7C} Install \Code{negate-polynomial} in the table as the generic {\tt negate} method for polynomials. Install {\tt -polynomial} and \Code{equ-polynomial?} as the generic {\tt sub} and \Code{equ?} operations on polynomials. Test your procedures on the polynomials \Code{p1}, \Code{p2}, and \Code{p3} of exercises 5.5 and 5.6. \subsection{More Operations across Different Types} To combine a polynomial, $p$, with a number, we coerce the number into a constant polynomial over the variable of $p$, and combine them as polynomials. \paragraph{Exercise 5.8A} Define a procedure $\Code{repnum->reppoly}: (\Var, \RN) \to \RP$ which coerces $n$ into a constant polynomial $n$ over a given variable. Define methods for generic \Code{add}, \Code{sub}, \Code{mul} and \Code{equ?} at types (\numtag\ \polytag) and (\polytag\ \numtag), and for generic \Code{div} at types (\polytag\ \numtag). \paragraph{Lab exercise 5.8B} Install your new methods. Test them on \Code{(square p2-mixed)} and \[\Code{(equ?\ (sub (add p1 p3) p1) p3)}.\] \paragraph{Exercise 5.8C} To multiply a rational by a number, it was ok to coerce the number $n$ into the rational $n/1$. Give an example illustrating why handling multiplication of a polynomial and a rational by coercing the polynomial $p$ into the rational $p/1$ is not always a good thing to do. How about coercing the rational into a constant polynomial over the variable of $p$? \subsection{Polynomial Evaluation} Polynomials are generic numbers on the one hand, but on the other hand, they also describe {\em functions} which can be applied to generic numbers. For example, the polynomial $p_1(x) = x^3 + 5x^2 - 2$ evaluates to 26 when $x=2$. Similarly, when $z = x+1$, the polynomial $p_2(z,x)$ evaluates to the polynomial \[x^5 + 7x^4 + 11x^3 + 3x^2 - x + 6.\] It is easy to define an \Code{apply-polynomial} procedure: \beginlisp (define (apply-term t gn) (mul (coeff t) (power gn (order t)))) \endlisp \beginlisp (define (power gn k) (if (< k 1) (create-number 1) (mul gn (power gn (dec 1))))) \endlisp \beginlisp (define (apply-terms terms gn) <**blob5.9A**>) \endlisp \beginlisp (define (apply-polynomial p gn) (apply-terms (term-list (contents p)) gn)) \endlisp \paragraph{Exercise 5.9A} Fill in \Code{<**blob5.9A**>} to complete the definition of \Code{apply-terms}. \paragraph{Exercise 5.9B} Test your definition by applying $p_1$ to 2, $p_2$ to $x+1$, and verifying \beginlisp (define x (create-numerical-polynomial 'x '(1 0))) (equ? (apply-polynomial p1 x) p1) \endlisp \end{document}