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.FunctionDemo;
|
||||
import org.gym.fp.fpjava.demo.RecursionDemo;
|
||||
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) {
|
||||
FunctionDemo.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