spike.Trampoline Maven / Gradle / Ivy
Show all versions of lambda Show documentation
package spike;
import com.jnape.palatable.lambda.adt.coproduct.CoProduct2;
import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functions.Fn2;
import com.jnape.palatable.lambda.functions.builtin.fn2.Unfoldr;
import spike.RecursiveResult.Recurse;
import spike.RecursiveResult.Terminate;
import java.util.function.Function;
/**
* Given a {@link Function}<A, {@link CoProduct2}<A, B, ?>>
(analogous to "recurse" and
* "return" tail position instructions, respectively), produce a {@link Function}<A, B>
that
* unrolls the original function by iteratively passing each result that matches the input (A
) back
* to the original function, and then terminating on and returning the first output (B
).
*
* This is isomorphic to - though presumably faster than - taking the last element of an {@link Unfoldr} call.
*
* @param the trampolined function's input type
* @param the trampolined function's output type
*/
public final class Trampoline implements Fn2>, A, B> {
private static final Trampoline INSTANCE = new Trampoline<>();
@Override
public B apply(Function super A, ? extends RecursiveResult> fn, A a) {
RecursiveResult next = fn.apply(a);
while (next instanceof Recurse)
next = fn.apply(((Recurse) next).a);
return ((Terminate) next).b;
}
@SuppressWarnings("unchecked")
public static Trampoline trampoline() {
return INSTANCE;
}
public static Fn1 trampoline(Function super A, ? extends RecursiveResult> fn) {
return Trampoline.trampoline().apply(fn);
}
public static B trampoline(Function super A, ? extends RecursiveResult> fn, A a) {
return trampoline(fn).apply(a);
}
}