package function.builtin.predicate; import static recursion.TailCalls.done; import static recursion.TailCalls.tailCall; import static sexpression.Nil.NIL; import static sexpression.Symbol.T; import function.ArgumentValidator; import function.FunctionNames; import function.LispFunction; import recursion.TailCall; import sexpression.Cons; import sexpression.LispNumber; import sexpression.SExpression; @FunctionNames({ "=" }) public class NUMERIC_EQUAL extends LispFunction { private ArgumentValidator argumentValidator; public NUMERIC_EQUAL(String name) { this.argumentValidator = new ArgumentValidator(name); this.argumentValidator.setMinimumNumberOfArguments(1); this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class); } @Override public SExpression call(Cons argumentList) { argumentValidator.validate(argumentList); return callTailRecursive(argumentList).invoke(); } private TailCall callTailRecursive(Cons argumentList) { Cons remainingArguments = (Cons) argumentList.getRest(); if (remainingArguments.isNull()) return done(T); SExpression firstArgument = argumentList.getFirst(); LispNumber number1 = (LispNumber) firstArgument; SExpression secondArgument = remainingArguments.getFirst(); LispNumber number2 = (LispNumber) secondArgument; if (!isEqual(number1, number2)) return done(NIL); return tailCall(() -> callTailRecursive(remainingArguments)); } private boolean isEqual(LispNumber number1, LispNumber number2) { return number1.getValue().equals(number2.getValue()); } }