Tail recursion abstraction
This commit is contained in:
@@ -2,12 +2,14 @@ package org.gym.fp.fpjava;
|
|||||||
|
|
||||||
import org.gym.fp.fpjava.demo.AbstractControlStructureDemo;
|
import org.gym.fp.fpjava.demo.AbstractControlStructureDemo;
|
||||||
import org.gym.fp.fpjava.demo.FunctionDemo;
|
import org.gym.fp.fpjava.demo.FunctionDemo;
|
||||||
|
import org.gym.fp.fpjava.demo.RecursionDemo;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
FunctionDemo.run();
|
FunctionDemo.run();
|
||||||
AbstractControlStructureDemo.run();
|
AbstractControlStructureDemo.run();
|
||||||
|
RecursionDemo.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.gym.fp.fpjava.demo;
|
||||||
|
|
||||||
|
import org.gym.fp.fpjava.type.TailCall;
|
||||||
|
|
||||||
|
import static org.gym.fp.fpjava.type.TailCall.ret;
|
||||||
|
import static org.gym.fp.fpjava.type.TailCall.suspend;
|
||||||
|
|
||||||
|
public class RecursionDemo {
|
||||||
|
|
||||||
|
public static void run() {
|
||||||
|
System.out.println(add(10, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int add(int x, int y) {
|
||||||
|
return addRec(x, y).eval();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TailCall<Integer> addRec(int x, int y) {
|
||||||
|
return y == 0
|
||||||
|
? ret(x)
|
||||||
|
: suspend(() -> addRec(x + 1, y - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package org.gym.fp.fpjava.type;
|
||||||
|
|
||||||
|
public abstract class TailCall<T> {
|
||||||
|
|
||||||
|
private TailCall() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> TailCall<T> ret(T t) {
|
||||||
|
return new Return<>(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> TailCall<T> suspend(Supplier<TailCall<T>> s) {
|
||||||
|
return new Suspend<>(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract TailCall<T> resume();
|
||||||
|
|
||||||
|
public abstract T eval();
|
||||||
|
|
||||||
|
public abstract boolean isSuspend();
|
||||||
|
|
||||||
|
private static class Return<T> extends TailCall<T> {
|
||||||
|
private final T t;
|
||||||
|
|
||||||
|
public Return(T t) {
|
||||||
|
this.t = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TailCall<T> resume() {
|
||||||
|
throw new IllegalStateException("Return has no resume");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T eval() {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuspend() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Suspend<T> extends TailCall<T> {
|
||||||
|
private final Supplier<TailCall<T>> resume;
|
||||||
|
|
||||||
|
public Suspend(Supplier<TailCall<T>> resume) {
|
||||||
|
this.resume = resume;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TailCall<T> resume() {
|
||||||
|
return resume.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T eval() {
|
||||||
|
TailCall<T> tailRec = this;
|
||||||
|
while (tailRec.isSuspend()) {
|
||||||
|
tailRec = tailRec.resume();
|
||||||
|
}
|
||||||
|
return tailRec.eval();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuspend() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user