Implement TCO for the length function
This commit is contained in:
parent
7de348d759
commit
6cd5fb66a4
|
@ -1,6 +1,11 @@
|
||||||
(defun problem (n)
|
(load "../lang/functions.lisp")
|
||||||
(if (< n 1) nil
|
|
||||||
(cons n (problem (- n 1)))))
|
|
||||||
|
|
||||||
(setq y (problem 20))
|
(defun build (n lst)
|
||||||
(setq x (problem 20000))
|
(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;
|
package function.builtin.cons;
|
||||||
|
|
||||||
import static function.builtin.cons.LIST.makeList;
|
import static function.builtin.cons.LIST.makeList;
|
||||||
|
import static recursion.tail.TailCalls.done;
|
||||||
|
import static recursion.tail.TailCalls.tailCall;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
|
||||||
import function.ArgumentValidator;
|
import function.ArgumentValidator;
|
||||||
import function.FunctionNames;
|
import function.FunctionNames;
|
||||||
import function.LispFunction;
|
import function.LispFunction;
|
||||||
|
import recursion.tail.TailCall;
|
||||||
import sexpression.Cons;
|
import sexpression.Cons;
|
||||||
import sexpression.LispNumber;
|
import sexpression.LispNumber;
|
||||||
|
|
||||||
|
@ -32,21 +35,21 @@ public class LENGTH extends LispFunction {
|
||||||
public LispNumber call(Cons argumentList) {
|
public LispNumber call(Cons argumentList) {
|
||||||
argumentValidator.validate(argumentList);
|
argumentValidator.validate(argumentList);
|
||||||
|
|
||||||
return callTailRecursive(BigInteger.ZERO, argumentList);
|
return callTailRecursive(BigInteger.ZERO, argumentList).invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
private LispNumber callWithoutArgumentValidation(Cons argumentList) {
|
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 list = (Cons) argumentList.getFirst();
|
||||||
Cons restOfList = makeList(list.getRest());
|
Cons restOfList = makeList(list.getRest());
|
||||||
|
|
||||||
if (list.isNull())
|
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) {
|
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