package function.builtin.math; import recursion.TailCall; import sexpression.Cons; import sexpression.LispNumber; import sexpression.SExpression; import java.util.function.BiFunction; import java.util.function.Function; import static recursion.TailCalls.done; import static recursion.TailCalls.tailCall; class MathFunction { Function singleValueOperation; BiFunction multipleValueOperation; public MathFunction(Function singleValueOperation, BiFunction multipleValueOperation) { this.singleValueOperation = singleValueOperation; this.multipleValueOperation = multipleValueOperation; } public TailCall callTailRecursive(Cons argumentList) { Cons remainingArguments = (Cons) argumentList.getRest(); SExpression firstArgument = argumentList.getFirst(); LispNumber number1 = (LispNumber) firstArgument; if (remainingArguments.isNull()) return done(singleValueOperation.apply(number1)); SExpression secondArgument = remainingArguments.getFirst(); LispNumber number2 = (LispNumber) secondArgument; LispNumber operationResult = multipleValueOperation.apply(number1, number2); SExpression remainingNumbers = remainingArguments.getRest(); if (remainingNumbers.isNull()) return done(operationResult); return tailCall(() -> callTailRecursive(new Cons(operationResult, remainingNumbers))); } }