66import fj .P1 ;
77import fj .data .Either ;
88
9- import static fj .Function .andThen ;
109import static fj .Function .curry ;
1110import static fj .data .Either .left ;
1211import static fj .data .Either .right ;
1312
1413/**
1514 * 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.
1616 */
1717public 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.
1821 private static abstract class Normal <A > extends Trampoline <A > {
1922 public abstract <R > R foldNormal (final F <A , R > pure , final F <P1 <Trampoline <A >>, R > k );
2023
@@ -23,8 +26,14 @@ public <B> Trampoline<B> bind(final F<A, Trampoline<B>> f) {
2326 }
2427 }
2528
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.
2631 private static final class Codense <A > extends Trampoline <A > {
32+
33+ // The Normal subcomputation
2734 private final Normal <Object > sub ;
35+
36+ // The current continuation
2837 private final F <Object , Trampoline <A >> cont ;
2938
3039 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,
3746 return gs .f (this );
3847 }
3948
49+ // The monadic bind constructs a new Codense whose subcomputation is still `sub`, and Kleisli-composes the
50+ // continuations.
4051 public <B > Trampoline <B > bind (final F <A , Trampoline <B >> f ) {
4152 return codense (sub , new F <Object , Trampoline <B >>() {
4253 public Trampoline <B > f (final Object o ) {
@@ -49,6 +60,8 @@ public Trampoline<B> _1() {
4960 });
5061 }
5162
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.
5265 public Either <P1 <Trampoline <A >>, A > resume () {
5366 return left (sub .resume ().either (new F <P1 <Trampoline <Object >>, P1 <Trampoline <A >>>() {
5467 public P1 <Trampoline <A >> f (final P1 <Trampoline <Object >> p ) {
@@ -93,7 +106,9 @@ public Trampoline<A> _1() {
93106 }
94107 }
95108
109+ // A suspended computation that can be resumed.
96110 private static final class Suspend <A > extends Normal <A > {
111+
97112 private final P1 <Trampoline <A >> suspension ;
98113
99114 private Suspend (final P1 <Trampoline <A >> s ) {
@@ -113,6 +128,7 @@ public Either<P1<Trampoline<A>>, A> resume() {
113128 }
114129 }
115130
131+ // A pure value at the leaf of a computation.
116132 private static final class Pure <A > extends Normal <A > {
117133 private final A value ;
118134
@@ -150,7 +166,7 @@ public Trampoline<A> f(final A a) {
150166 }
151167
152168 /**
153- * Constructs a leaf computation that results in the given value.
169+ * Constructs a pure computation that results in the given value.
154170 *
155171 * @param a The value of the result.
156172 * @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) {
307323 });
308324 }
309325
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+ */
310333 @ SuppressWarnings ("LoopStatementThatDoesntLoop" )
311334 public <B , C > Trampoline <C > zipWith (final Trampoline <B > b , final F2 <A , B , C > f ) {
312335 final Either <P1 <Trampoline <A >>, A > ea = resume ();
313336 final Either <P1 <Trampoline <B >>, B > eb = b .resume ();
314337 Trampoline <C > r ;
315338 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 ()) {
317340 return suspend (P1 .bind (x , y , new F2 <Trampoline <A >, Trampoline <B >, Trampoline <C >>() {
318341 public Trampoline <C > f (final Trampoline <A > ta , final Trampoline <B > tb ) {
319342 return ta .bind (tb , new F2 <A , B , C >() {
@@ -324,23 +347,23 @@ public C f(final A a, final B b) {
324347 }
325348 }.curry ()));
326349 }
327- for (final B y : eb .right ()) {
350+ for (final B y : eb .right ()) {
328351 return suspend (x .map (new F <Trampoline <A >, Trampoline <C >>() {
329352 public Trampoline <C > f (final Trampoline <A > ta ) {
330353 return ta .map (f .flip ().f (y ));
331354 }
332355 }));
333356 }
334357 }
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 ()) {
337360 return suspend (new P1 <Trampoline <C >>() {
338361 public Trampoline <C > _1 () {
339362 return pure (f .f (x , y ));
340363 }
341364 });
342365 }
343- for (final P1 <Trampoline <B >> y : eb .left ()) {
366+ for (final P1 <Trampoline <B >> y : eb .left ()) {
344367 return suspend (y .map (liftM2 (f .curry ()).f (pure (x ))));
345368 }
346369 }
0 commit comments