Implement TCO for the length function
This commit is contained in:
parent
7de348d759
commit
6cd5fb66a4
|
@ -1,6 +1,11 @@
|
|||
(defun problem (n)
|
||||
(if (< n 1) nil
|
||||
(cons n (problem (- n 1)))))
|
||||
(load "../lang/functions.lisp")
|
||||
|
||||
(setq y (problem 20))
|
||||
(setq x (problem 20000))
|
||||
(defun build (n lst)
|
||||
(if (= n 0) lst
|
||||
(build (- n 1) (cons (car lst) lst))))
|
||||
|
||||
(defun build2 (n lst)
|
||||
(if (= n 0) lst
|
||||
(build2 (- n 1) (build 200 lst))))
|
||||
|
||||
(length (build2 200 (build2 200 '(1 1 1 1 0 0 0 0))))
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
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;
|
||||
|
||||
|
@ -32,21 +35,21 @@ public class LENGTH extends LispFunction {
|
|||
public LispNumber call(Cons argumentList) {
|
||||
argumentValidator.validate(argumentList);
|
||||
|
||||
return callTailRecursive(BigInteger.ZERO, argumentList);
|
||||
return callTailRecursive(BigInteger.ZERO, argumentList).invoke();
|
||||
}
|
||||
|
||||
private LispNumber callWithoutArgumentValidation(Cons argumentList) {
|
||||
return callTailRecursive(BigInteger.ZERO, argumentList);
|
||||
return callTailRecursive(BigInteger.ZERO, argumentList).invoke();
|
||||
}
|
||||
|
||||
private LispNumber callTailRecursive(BigInteger accumulatedLength, Cons argumentList) {
|
||||
private TailCall<LispNumber> callTailRecursive(BigInteger accumulatedLength, Cons argumentList) {
|
||||
Cons list = (Cons) argumentList.getFirst();
|
||||
Cons restOfList = makeList(list.getRest());
|
||||
|
||||
if (list.isNull())
|
||||
return new LispNumber(accumulatedLength);
|
||||
return done(new LispNumber(accumulatedLength));
|
||||
|
||||
return callTailRecursive(increment(accumulatedLength), restOfList);
|
||||
return tailCall(() -> callTailRecursive(increment(accumulatedLength), restOfList));
|
||||
}
|
||||
|
||||
private BigInteger increment(BigInteger number) {
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package recursion.tail;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface TailCall<T> {
|
||||
|
||||
TailCall<T> apply();
|
||||
|
||||
default boolean isComplete() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default T result() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
default T invoke() {
|
||||
return Stream.iterate(this, TailCall::apply).filter(TailCall::isComplete).findFirst().get().result();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package recursion.tail;
|
||||
|
||||
public class TailCalls {
|
||||
|
||||
public static <T> TailCall<T> tailCall(TailCall<T> nextCall) {
|
||||
return nextCall;
|
||||
}
|
||||
|
||||
public static <T> TailCall<T> done(T value) {
|
||||
return new TailCall<T>() {
|
||||
|
||||
@Override
|
||||
public boolean isComplete() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T result() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TailCall<T> apply() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue