6
6
import fj .P1 ;
7
7
import fj .data .Either ;
8
8
9
- import static fj .Function .andThen ;
10
9
import static fj .Function .curry ;
11
10
import static fj .data .Either .left ;
12
11
import static fj .data .Either .right ;
13
12
14
13
/**
15
14
* A Trampoline is a potentially branching computation that can be stepped through and executed in constant stack.
15
+ * It represent suspendable coroutines with subroutine calls, reified as a data structure.
16
16
*/
17
17
public abstract class Trampoline <A > {
18
+
19
+ // A Normal Trampoline is either done or suspended, and is allowed to be a subcomputation of a Codense.
20
+ // This is the pointed functor part of the Trampoline monad.
18
21
private static abstract class Normal <A > extends Trampoline <A > {
19
22
public abstract <R > R foldNormal (final F <A , R > pure , final F <P1 <Trampoline <A >>, R > k );
20
23
@@ -23,8 +26,14 @@ public <B> Trampoline<B> bind(final F<A, Trampoline<B>> f) {
23
26
}
24
27
}
25
28
29
+ // A Codense Trampoline delimits a subcomputation and tracks its current continuation. Subcomputations are only
30
+ // allowed to be Normal, so all of the continuations accumulate on the right.
26
31
private static final class Codense <A > extends Trampoline <A > {
32
+
33
+ // The Normal subcomputation
27
34
private final Normal <Object > sub ;
35
+
36
+ // The current continuation
28
37
private final F <Object , Trampoline <A >> cont ;
29
38
30
39
private Codense (final Normal <Object > t , final F <Object , Trampoline <A >> k ) {
@@ -37,6 +46,8 @@ public <R> R fold(final F<Normal<A>, R> n,
37
46
return gs .f (this );
38
47
}
39
48
49
+ // The monadic bind constructs a new Codense whose subcomputation is still `sub`, and Kleisli-composes the
50
+ // continuations.
40
51
public <B > Trampoline <B > bind (final F <A , Trampoline <B >> f ) {
41
52
return codense (sub , new F <Object , Trampoline <B >>() {
42
53
public Trampoline <B > f (final Object o ) {
@@ -49,6 +60,8 @@ public Trampoline<B> _1() {
49
60
});
50
61
}
51
62
63
+ // The resumption of a Codense is the resumption of its subcomputation. If that computation is done, its result
64
+ // gets shifted into the continuation.
52
65
public Either <P1 <Trampoline <A >>, A > resume () {
53
66
return left (sub .resume ().either (new F <P1 <Trampoline <Object >>, P1 <Trampoline <A >>>() {
54
67
public P1 <Trampoline <A >> f (final P1 <Trampoline <Object >> p ) {
@@ -93,7 +106,9 @@ public Trampoline<A> _1() {
93
106
}
94
107
}
95
108
109
+ // A suspended computation that can be resumed.
96
110
private static final class Suspend <A > extends Normal <A > {
111
+
97
112
private final P1 <Trampoline <A >> suspension ;
98
113
99
114
private Suspend (final P1 <Trampoline <A >> s ) {
@@ -113,6 +128,7 @@ public Either<P1<Trampoline<A>>, A> resume() {
113
128
}
114
129
}
115
130
131
+ // A pure value at the leaf of a computation.
116
132
private static final class Pure <A > extends Normal <A > {
117
133
private final A value ;
118
134
@@ -150,7 +166,7 @@ public Trampoline<A> f(final A a) {
150
166
}
151
167
152
168
/**
153
- * Constructs a leaf computation that results in the given value.
169
+ * Constructs a pure computation that results in the given value.
154
170
*
155
171
* @param a The value of the result.
156
172
* @return A trampoline that results in the given value.
@@ -307,13 +323,20 @@ public Trampoline<C> f(final Trampoline<A> as, final Trampoline<B> bs) {
307
323
});
308
324
}
309
325
326
+ /**
327
+ * Combines two trampolines so they run cooperatively. The results are combined with the given function.
328
+ *
329
+ * @param b Another trampoline to combine with this trampoline.
330
+ * @param f A function to combine the results of the two trampolines.
331
+ * @return A new trampoline that runs this trampoline and the given trampoline simultaneously.
332
+ */
310
333
@ SuppressWarnings ("LoopStatementThatDoesntLoop" )
311
334
public <B , C > Trampoline <C > zipWith (final Trampoline <B > b , final F2 <A , B , C > f ) {
312
335
final Either <P1 <Trampoline <A >>, A > ea = resume ();
313
336
final Either <P1 <Trampoline <B >>, B > eb = b .resume ();
314
337
Trampoline <C > r ;
315
338
for (final P1 <Trampoline <A >> x : ea .left ()) {
316
- for (final P1 <Trampoline <B >> y : eb .left ()) {
339
+ for (final P1 <Trampoline <B >> y : eb .left ()) {
317
340
return suspend (P1 .bind (x , y , new F2 <Trampoline <A >, Trampoline <B >, Trampoline <C >>() {
318
341
public Trampoline <C > f (final Trampoline <A > ta , final Trampoline <B > tb ) {
319
342
return ta .bind (tb , new F2 <A , B , C >() {
@@ -324,23 +347,23 @@ public C f(final A a, final B b) {
324
347
}
325
348
}.curry ()));
326
349
}
327
- for (final B y : eb .right ()) {
350
+ for (final B y : eb .right ()) {
328
351
return suspend (x .map (new F <Trampoline <A >, Trampoline <C >>() {
329
352
public Trampoline <C > f (final Trampoline <A > ta ) {
330
353
return ta .map (f .flip ().f (y ));
331
354
}
332
355
}));
333
356
}
334
357
}
335
- for (final A x : ea .right ()) {
336
- for (final B y : eb .right ()) {
358
+ for (final A x : ea .right ()) {
359
+ for (final B y : eb .right ()) {
337
360
return suspend (new P1 <Trampoline <C >>() {
338
361
public Trampoline <C > _1 () {
339
362
return pure (f .f (x , y ));
340
363
}
341
364
});
342
365
}
343
- for (final P1 <Trampoline <B >> y : eb .left ()) {
366
+ for (final P1 <Trampoline <B >> y : eb .left ()) {
344
367
return suspend (y .map (liftM2 (f .curry ()).f (pure (x ))));
345
368
}
346
369
}
0 commit comments