Reputation: 409
I have a defined Datatype
datatype expression = Constant of int
| Variable of string
| Operator of string * expression
| Pair of expression list
| List of expression list
I am given two fractions that have a form of:
Operator("/", Pair [Constant x, Constant y])
or
Operator("/", Pair [Variable x, Constant y])
I need to sum these two fractions and return a new expression that has the least common multiple of the two denominators as its denominator.
I managed to make it work, however my code seems needlessly complicated and convoluted. Is there a way to write this shorter?
What I managed to do so far:
fun add (a,b) =
case (a,b) of
(Operator("/", Pair [Constant x1, Constant y1]),
Operator("/", Pair [Constant x2, Constant y2]))
=> Operator("/", Pair [Constant ((x1*((lcm(y1,y2) div y1)))+(x2*(lcm(y1,y2) div y2))), Constant (lcm(y1,y2))])
| (Operator("/", Pair [Variable x1, Constant y1]),
Operator("/", Pair [Constant x2, Constant y2 ]))
=> Operator("/", Pair[
Operator("+", Pair[
Operator("*", Pair[Variable x1, Constant (lcm(y1,y2) div y1)]),
Constant (x2* (lcm(y1,y2) div y2)) ]),
Constant (lcm(y1,y2))])
| (Operator("/", Pair [Constant x1, Constant y1]),
Operator("/", Pair [Variable x2, Constant y2 ]))
=> Operator("/", Pair[
Operator("+", Pair[
Operator("*", Pair[Variable x2, Constant (lcm(y1,y2) div y2)]),
Constant (x1* (lcm(y1,y2) div y2)) ]),
Constant (lcm(y1,y2))])
| (Operator("/", Pair [Variable x1, Constant y1]),
Operator("/", Pair [Variable x2, Constant y2 ]))
=> Operator("/", Pair[
Operator("+", Pair[
Operator("*", Pair[Variable x1, Constant (lcm(y1,y2) div y1)]),
Operator("*", Pair[Variable x2, Constant (lcm(y1,y2) div y2)])]),
Constant (lcm(y1,y2))])
Upvotes: 2
Views: 269
Reputation: 16125
Is there a way to write this shorter?
Yes. Aim for the simplest possible pattern. E.g. if you are building an abstract syntax tree,
fun add (e1, e2) = Operator ("+", Pair [e1, e2])
And if you are evaluating a syntax tree,
fun eval env exp =
case exp of
Constant i => i
| Variable x => lookup x env
| Operator (oper, exps) => evalOp env oper (map (eval env) exps)
| ... => ???
and evalOp env "+" is = foldl op+ 0 is
| evalOp env "-" is = foldl op- 0 is
| ...
Particularly: You may want to reconsider what meaningful scalar values that pairs and lists may evaluate to and if, perhaps, pairs and lists should be restricted to portions of the syntax tree.
Generally: Every time your patterns match one level deeper, the number of match cases is multiplied by the number of constructors. One or two levels of matching will usually suffice. If not, writing helper functions that perform deeper matching is almost always the sane choice.
Upvotes: 4