package function.builtin.predicate; import function.ArgumentValidator; import function.FunctionNames; import function.LispFunction; import recursion.TailCall; import sexpression.Cons; import sexpression.LispNumber; import sexpression.Nil; import sexpression.SExpression; import sexpression.Symbol; import static recursion.TailCalls.done; import static recursion.TailCalls.tailCall; @FunctionNames({ "<" }) public class NUMERIC_LESS extends LispFunction { private ArgumentValidator argumentValidator; public NUMERIC_LESS(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<SExpression> callTailRecursive(Cons argumentList) { Cons remainingArguments = (Cons) argumentList.getRest(); if (remainingArguments.isNull()) return done(Symbol.Companion.getT()); SExpression firstArgument = argumentList.getFirst(); SExpression secondArgument = remainingArguments.getFirst(); LispNumber number1 = (LispNumber) firstArgument; LispNumber number2 = (LispNumber) secondArgument; if (!isFirstLesser(number1, number2)) return done(Nil.INSTANCE); return tailCall(() -> callTailRecursive(remainingArguments)); } private boolean isFirstLesser(LispNumber number1, LispNumber number2) { return number1.getValue().compareTo(number2.getValue()) < 0; } }