CS 307: 13. Symbolic Algebra in Java
Due: Friday, December 7, 2001.
This assignment illustrates tree recursion and the use of run-time
polymorphism of the kind with which we are familiar in Scheme.
The directory (folder) exp contains files
L.java, Cons.java, Symbol.java, and
Number.java. (Note that this file Cons.java is
different from the one used in the previous assignment; be sure to
keep it in a different folder so that you do not over-write your
previous assignment.)
These files implement a small subset of Scheme types as Java
classes. L is the top class, representing any Lisp object;
Cons, Symbol, and Number are subclasses
of L.
Study the classes that are provided so that you can see how the
Scheme functions and concepts that you are familiar with are implemented.
Some useful functions are provided in the file Cons.java, both
as examples of how to write code in this system and as functions that
may be useful in your programs.
This assignment will re-implement some of the functions that were
written for our Assignment 8 on Symbolic Algebra.
It may be helpful for you to consult your solution to Assignment 8
while writing these programs. The class notes are also legitimate
sources for some of these functions.
Implement the following methods in Java; add them to the file
Cons.java, which also has test cases for these
in its main() method.
- assoc(item, lst) Use L.eqv to test for item.
- union(lst, second)
- copy_tree(tree)
- subst(x, y, tree) substitutes x for y in
tree structure tree. y is a simple item that
can be tested with L.eqv.
- sublis(alist, tree) For this version of sublis,
we will assume that the alist argument contains lists of
two items, ((var value) ... ), rather than
"dotted pair" items.
- vars(exp) returns a list of the variables in a
well-formed formula or expression exp.
(vars 'a) => (a) (vars '(+ a a)) => (a)
(vars '(= a b)) => (a b) (vars '(+ a 2)) => (a)
- Write an interpreter function evalexp(exp) that
evaluates an expression exp containing only constant numeric
values and the operators + - * /; - can be either unary
or binary.
evalexp( (+ 3 (* 4 5)) ) => 23
- Write a recursive function solve(exp, var) that attempts to
solve the equation exp for variable var, which we assume
occurs at most once in exp. The basic idea of solve is to
test for equations that are already solved or unsolvable (base cases);
otherwise, solve will search for a solution by applying laws of
algebra. solve is a kind of tree recursion -- not recursion
on car and cdr, but recursion on the applicable
operators (transformations of the input formula into new formulas).
- If the left-hand side (lhs) of exp is var,
return exp.
(solve '(= f (* m a)) 'f) => (= f (* m a))
- If the right-hand side (rhs) of exp is var, return
exp with its arguments reversed.
(solve '(= (* m a) f) 'f) = (= f (* m a))
- If the rhs is not var and not a list, return null.
- If the rhs of exp is a list (i.e. an operation), try to solve
the equation by applying algebraic
laws, which will make a new equation by moving things to the left side.
Then try to solve that equation. For binary operators, there will
be two possibilities, both of which must be tried. For example, given the
original equation x = y - z, we could (a) add z to both sides
to give x + z = y, or (b) subtract y from both sides to give
x - y = - z and then negate both sides to give y - x = z
(these two operations can be combined as a single transformation).
(solve '(= x (- y z)) 'y)
(solve '(= (- y x) z) 'y) ; first try: null
(solve '(= (+ x z) y) 'y) ; second try: succeeds
=> (= y (+ x z))
You should handle the operators + - * /.
The operator - can be either unary (having only one argument,
i.e. minus) or binary (having two arguments, i.e. difference),
which must be treated differently. We will assume that all other operators
will have two arguments.
Demonstrate that you can solve the test cases provided in the file
Cons.java .
- Write a function infix(exp, parens) that will convert an
expression into a string in infix form. Include parentheses around
an expression only if it involves an operation and parens is
true. For recursive calls to infix, you can always
make parens be true.