transcendental-lisp/src/function/builtin/cons/LENGTH.java

60 lines
1.8 KiB
Java

package function.builtin.cons;
import static function.builtin.cons.LIST.makeList;
import static recursion.tail.TailCalls.done;
import static recursion.tail.TailCalls.tailCall;
import java.math.BigInteger;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispFunction;
import recursion.tail.TailCall;
import sexpression.Cons;
import sexpression.LispNumber;
@FunctionNames({ "LENGTH" })
public class LENGTH extends LispFunction {
public static BigInteger getLength(Cons list) {
LENGTH lengthFunction = new LENGTH("LENGTH");
LispNumber length = lengthFunction.callWithoutArgumentValidation(makeList(list));
return length.getValue();
}
private ArgumentValidator argumentValidator;
public LENGTH(String name) {
this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setExactNumberOfArguments(1);
this.argumentValidator.setEveryArgumentExpectedType(Cons.class);
}
@Override
public LispNumber call(Cons argumentList) {
argumentValidator.validate(argumentList);
return callTailRecursive(BigInteger.ZERO, argumentList).invoke();
}
private LispNumber callWithoutArgumentValidation(Cons argumentList) {
return callTailRecursive(BigInteger.ZERO, argumentList).invoke();
}
private TailCall<LispNumber> callTailRecursive(BigInteger accumulatedLength, Cons argumentList) {
Cons list = (Cons) argumentList.getFirst();
Cons restOfList = makeList(list.getRest());
if (list.isNull())
return done(new LispNumber(accumulatedLength));
return tailCall(() -> callTailRecursive(increment(accumulatedLength), restOfList));
}
private BigInteger increment(BigInteger number) {
return number.add(BigInteger.ONE);
}
}