com.jnape.palatable.lambda.functions.recursion.Trampoline Maven / Gradle / Ivy
Show all versions of lambda Show documentation
package com.jnape.palatable.lambda.functions.recursion;
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 com.jnape.palatable.lambda.functions.recursion.RecursiveResult.Recurse;
import com.jnape.palatable.lambda.functions.recursion.RecursiveResult.Terminate;
/**
* Given an {@link Fn1}<A, {@link CoProduct2}<A, B, ?>>
(analogous to "recurse" and "return"
* tail position instructions, respectively), produce a {@link Fn1}<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 checkedApply(Fn1 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 (Trampoline) INSTANCE;
}
public static Fn1 trampoline(Fn1 super A, ? extends RecursiveResult> fn) {
return Trampoline.trampoline().apply(fn);
}
public static B trampoline(Fn1 super A, ? extends RecursiveResult> fn, A a) {
return trampoline(fn).apply(a);
}
}