forked from palatable/lambda
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTrampoline.java
More file actions
47 lines (39 loc) · 1.9 KB
/
Trampoline.java
File metadata and controls
47 lines (39 loc) · 1.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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 <code>{@link Function}<A, {@link CoProduct2}<A, B, ?>></code> (analogous to "recurse" and
* "return" tail position instructions, respectively), produce a <code>{@link Function}<A, B></code> that
* unrolls the original function by iteratively passing each result that matches the input (<code>A</code>) back
* to the original function, and then terminating on and returning the first output (<code>B</code>).
* <p>
* This is isomorphic to - though presumably faster than - taking the last element of an {@link Unfoldr} call.
*
* @param <A> the trampolined function's input type
* @param <B> the trampolined function's output type
*/
public final class Trampoline<A, B> implements Fn2<Function<? super A, ? extends RecursiveResult<A, B>>, A, B> {
private static final Trampoline INSTANCE = new Trampoline<>();
@Override
public B apply(Function<? super A, ? extends RecursiveResult<A, B>> fn, A a) {
RecursiveResult<A, B> next = fn.apply(a);
while (next instanceof Recurse)
next = fn.apply(((Recurse<A, B>) next).a);
return ((Terminate<A, B>) next).b;
}
@SuppressWarnings("unchecked")
public static <A, B> Trampoline<A, B> trampoline() {
return INSTANCE;
}
public static <A, B> Fn1<A, B> trampoline(Function<? super A, ? extends RecursiveResult<A, B>> fn) {
return Trampoline.<A, B>trampoline().apply(fn);
}
public static <A, B> B trampoline(Function<? super A, ? extends RecursiveResult<A, B>> fn, A a) {
return trampoline(fn).apply(a);
}
}