diff --git a/lisp/random/problem.lisp b/lisp/random/problem.lisp index e297504..ad4b69a 100644 --- a/lisp/random/problem.lisp +++ b/lisp/random/problem.lisp @@ -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)))) diff --git a/src/function/builtin/cons/LENGTH.java b/src/function/builtin/cons/LENGTH.java index 1bcd156..3496bc9 100644 --- a/src/function/builtin/cons/LENGTH.java +++ b/src/function/builtin/cons/LENGTH.java @@ -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 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) { diff --git a/src/recursion/tail/TailCall.java b/src/recursion/tail/TailCall.java new file mode 100644 index 0000000..0f8f7ef --- /dev/null +++ b/src/recursion/tail/TailCall.java @@ -0,0 +1,22 @@ +package recursion.tail; + +import java.util.stream.Stream; + +@FunctionalInterface +public interface TailCall { + + TailCall 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(); + } + +} \ No newline at end of file diff --git a/src/recursion/tail/TailCalls.java b/src/recursion/tail/TailCalls.java new file mode 100644 index 0000000..482043c --- /dev/null +++ b/src/recursion/tail/TailCalls.java @@ -0,0 +1,29 @@ +package recursion.tail; + +public class TailCalls { + + public static TailCall tailCall(TailCall nextCall) { + return nextCall; + } + + public static TailCall done(T value) { + return new TailCall() { + + @Override + public boolean isComplete() { + return true; + } + + @Override + public T result() { + return value; + } + + @Override + public TailCall apply() { + throw new UnsupportedOperationException(); + } + }; + } + +} \ No newline at end of file