Refactored the code for math functions

This commit is contained in:
Mike Cifelli 2017-01-15 13:50:28 -05:00
parent 0560c02093
commit 4b75b13485
5 changed files with 59 additions and 78 deletions

View File

@ -8,36 +8,19 @@ import sexpression.*;
public class DIVIDE extends LispFunction { public class DIVIDE extends LispFunction {
private ArgumentValidator argumentValidator; private ArgumentValidator argumentValidator;
private MathFunction mathFunction;
public DIVIDE() { public DIVIDE() {
this.argumentValidator = new ArgumentValidator("/"); this.argumentValidator = new ArgumentValidator("/");
this.argumentValidator.setMinimumNumberOfArguments(1); this.argumentValidator.setMinimumNumberOfArguments(1);
this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class); this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class);
this.mathFunction = new MathFunction(this::getReciprocal, this::divide);
} }
public SExpression call(Cons argumentList) { public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList); argumentValidator.validate(argumentList);
return callTailRecursive(argumentList); return mathFunction.callTailRecursive(argumentList);
}
private SExpression callTailRecursive(Cons argumentList) {
Cons remainingArguments = (Cons) argumentList.getCdr();
SExpression firstArgument = argumentList.getCar();
LispNumber number1 = (LispNumber) firstArgument;
if (remainingArguments.nullp())
return getReciprocal(number1);
SExpression secondArgument = remainingArguments.getCar();
LispNumber number2 = (LispNumber) secondArgument;
LispNumber quotient = divide(number1, number2);
SExpression remainingNumbers = remainingArguments.getCdr();
if (remainingNumbers.nullp())
return quotient;
return callTailRecursive(new Cons(quotient, remainingNumbers));
} }
private LispNumber getReciprocal(LispNumber number1) { private LispNumber getReciprocal(LispNumber number1) {

View File

@ -8,40 +8,27 @@ import sexpression.*;
public class MINUS extends LispFunction { public class MINUS extends LispFunction {
private ArgumentValidator argumentValidator; private ArgumentValidator argumentValidator;
private MathFunction mathFunction;
public MINUS() { public MINUS() {
this.argumentValidator = new ArgumentValidator("-"); this.argumentValidator = new ArgumentValidator("-");
this.argumentValidator.setMinimumNumberOfArguments(1); this.argumentValidator.setMinimumNumberOfArguments(1);
this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class); this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class);
this.mathFunction = new MathFunction(this::additiveInverse, this::subtract);
} }
public SExpression call(Cons argumentList) { public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList); argumentValidator.validate(argumentList);
return callTailRecursive(argumentList); return mathFunction.callTailRecursive(argumentList);
}
private SExpression callTailRecursive(Cons argumentList) {
Cons remainingArguments = (Cons) argumentList.getCdr();
SExpression firstArgument = argumentList.getCar();
LispNumber number1 = (LispNumber) firstArgument;
if (remainingArguments.nullp())
return additiveInverse(number1);
SExpression secondArgument = remainingArguments.getCar();
LispNumber number2 = (LispNumber) secondArgument;
LispNumber difference = new LispNumber(number1.getValue().subtract(number2.getValue()));
SExpression remainingNumbers = remainingArguments.getCdr();
if (!remainingNumbers.consp())
return difference;
return callTailRecursive(new Cons(difference, remainingNumbers));
} }
private LispNumber additiveInverse(LispNumber number) { private LispNumber additiveInverse(LispNumber number) {
return new LispNumber(BigInteger.ZERO.subtract(number.getValue())); return new LispNumber(BigInteger.ZERO.subtract(number.getValue()));
} }
private LispNumber subtract(LispNumber number1, LispNumber number2) {
return new LispNumber(number1.getValue().subtract(number2.getValue()));
}
} }

View File

@ -6,35 +6,22 @@ import sexpression.*;
public class MULTIPLY extends LispFunction { public class MULTIPLY extends LispFunction {
private ArgumentValidator argumentValidator; private ArgumentValidator argumentValidator;
private MathFunction mathFunction;
public MULTIPLY() { public MULTIPLY() {
this.argumentValidator = new ArgumentValidator("*"); this.argumentValidator = new ArgumentValidator("*");
this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class); this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class);
this.mathFunction = new MathFunction(number -> number, this::multiply);
} }
public LispNumber call(Cons argumentList) { public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList); argumentValidator.validate(argumentList);
return callTailRecursive(new Cons(LispNumber.ONE, argumentList)); return mathFunction.callTailRecursive(new Cons(LispNumber.ONE, argumentList));
} }
private LispNumber callTailRecursive(Cons argumentList) { private LispNumber multiply(LispNumber number1, LispNumber number2) {
Cons remainingArguments = (Cons) argumentList.getCdr(); return new LispNumber(number1.getValue().multiply(number2.getValue()));
SExpression firstArgument = argumentList.getCar();
LispNumber number1 = (LispNumber) firstArgument;
if (remainingArguments.nullp())
return number1;
SExpression secondArgument = remainingArguments.getCar();
LispNumber number2 = (LispNumber) secondArgument;
LispNumber product = new LispNumber(number1.getValue().multiply(number2.getValue()));
SExpression remainingNumbers = remainingArguments.getCdr();
if (!remainingNumbers.consp())
return product;
return callTailRecursive(new Cons(product, remainingNumbers));
} }
} }

View File

@ -0,0 +1,37 @@
package function.builtin.math;
import java.util.function.*;
import sexpression.*;
class MathFunction {
Function<LispNumber, LispNumber> singleValueOperation;
BiFunction<LispNumber, LispNumber, LispNumber> multipleValueOperation;
public MathFunction(Function<LispNumber, LispNumber> singleValueOperation,
BiFunction<LispNumber, LispNumber, LispNumber> multipleValueOperation) {
this.singleValueOperation = singleValueOperation;
this.multipleValueOperation = multipleValueOperation;
}
public SExpression callTailRecursive(Cons argumentList) {
Cons remainingArguments = (Cons) argumentList.getCdr();
SExpression firstArgument = argumentList.getCar();
LispNumber number1 = (LispNumber) firstArgument;
if (remainingArguments.nullp())
return singleValueOperation.apply(number1);
SExpression secondArgument = remainingArguments.getCar();
LispNumber number2 = (LispNumber) secondArgument;
LispNumber operationResult = multipleValueOperation.apply(number1, number2);
SExpression remainingNumbers = remainingArguments.getCdr();
if (remainingNumbers.nullp())
return operationResult;
return callTailRecursive(new Cons(operationResult, remainingNumbers));
}
}

View File

@ -6,35 +6,22 @@ import sexpression.*;
public class PLUS extends LispFunction { public class PLUS extends LispFunction {
private ArgumentValidator argumentValidator; private ArgumentValidator argumentValidator;
private MathFunction mathFunction;
public PLUS() { public PLUS() {
this.argumentValidator = new ArgumentValidator("+"); this.argumentValidator = new ArgumentValidator("+");
this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class); this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class);
this.mathFunction = new MathFunction(number -> number, this::add);
} }
public LispNumber call(Cons argumentList) { public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList); argumentValidator.validate(argumentList);
return callTailRecursive(new Cons(LispNumber.ZERO, argumentList)); return mathFunction.callTailRecursive(new Cons(LispNumber.ZERO, argumentList));
} }
private LispNumber callTailRecursive(Cons argumentList) { private LispNumber add(LispNumber number1, LispNumber number2) {
Cons remainingArguments = (Cons) argumentList.getCdr(); return new LispNumber(number1.getValue().add(number2.getValue()));
SExpression firstArgument = argumentList.getCar();
LispNumber number1 = (LispNumber) firstArgument;
if (remainingArguments.nullp())
return number1;
SExpression secondArgument = remainingArguments.getCar();
LispNumber number2 = (LispNumber) secondArgument;
LispNumber sum = new LispNumber(number1.getValue().add(number2.getValue()));
SExpression remainingNumbers = remainingArguments.getCdr();
if (!remainingNumbers.consp())
return sum;
return callTailRecursive(new Cons(sum, remainingNumbers));
} }
} }