1
+ package com .jnape .palatable .lambda .monad ;
2
+
3
+ import com .jnape .palatable .lambda .adt .Either ;
4
+ import com .jnape .palatable .lambda .adt .coproduct .CoProduct2 ;
5
+ import com .jnape .palatable .lambda .functions .Fn1 ;
6
+ import com .jnape .palatable .lambda .functions .recursion .RecursiveResult ;
7
+ import com .jnape .palatable .lambda .functions .recursion .Trampoline ;
8
+ import com .jnape .palatable .lambda .functions .specialized .Lift ;
9
+ import com .jnape .palatable .lambda .functions .specialized .Pure ;
10
+ import com .jnape .palatable .lambda .functor .Applicative ;
11
+ import com .jnape .palatable .lambda .functor .builtin .Lazy ;
12
+ import com .jnape .palatable .lambda .monad .transformer .MonadT ;
13
+
14
+ import static com .jnape .palatable .lambda .adt .Either .left ;
15
+ import static com .jnape .palatable .lambda .adt .Either .right ;
16
+ import static com .jnape .palatable .lambda .functions .recursion .RecursiveResult .recurse ;
17
+ import static com .jnape .palatable .lambda .functions .recursion .RecursiveResult .terminate ;
18
+
19
+ /**
20
+ * A stack-safe {@link MonadT monad transformer} that can safely interpret deeply nested left- or right-associated
21
+ * binds for any {@link MonadRec}.
22
+ * <p>
23
+ * Example:
24
+ * <pre>
25
+ * {@code
26
+ * Times.<Fn1<Integer, Integer>>times(100_000, f -> f.fmap(x -> x + 1), id()).apply(0); // stack-overflow
27
+ * Times.<SafeT<Fn1<Integer, ?>, Integer>>times(100_000, f -> f.fmap(x -> x + 1), safeT(id()))
28
+ * .<Fn1<Integer, Integer>>runSafeT()
29
+ * .apply(0); // 100_000
30
+ * }
31
+ * </pre>
32
+ * <p>
33
+ * Inspired by Phil Freeman's paper
34
+ * <a href="http://functorial.com/stack-safety-for-free/index.pdf">Stack Safety for Free</a>.
35
+ *
36
+ * @param <M> the {@link MonadRec} instance
37
+ * @param <A> the carrier type
38
+ */
39
+ public final class SafeT <M extends MonadRec <?, M >, A > implements
40
+ MonadT <M , A , SafeT <M , ?>, SafeT <?, ?>> {
41
+
42
+ private final Body <M , A > body ;
43
+ private final Pure <M > pureM ;
44
+
45
+ private SafeT (Body <M , A > body , Pure <M > pureM ) {
46
+ this .body = body ;
47
+ this .pureM = pureM ;
48
+ }
49
+
50
+ /**
51
+ * Recover the full structure of the embedded {@link Monad} in a stack-safe way.
52
+ *
53
+ * @param <MA> the witnessed target type
54
+ * @return the embedded {@link Monad}
55
+ */
56
+ public <MA extends MonadRec <A , M >> MA runSafeT () {
57
+ return body .resume ().match (
58
+ fFree -> fFree .trampolineM (freeF -> freeF .resume ().match (
59
+ monadRec -> monadRec .fmap (RecursiveResult ::recurse ),
60
+ a -> pureM .<A , MonadRec <A , M >>apply (a ).fmap (RecursiveResult ::terminate ))).coerce (),
61
+ pureM ::apply );
62
+ }
63
+
64
+ /**
65
+ * {@inheritDoc}
66
+ */
67
+ @ Override
68
+ public <B > SafeT <M , B > fmap (Fn1 <? super A , ? extends B > fn ) {
69
+ return MonadT .super .<B >fmap (fn ).coerce ();
70
+ }
71
+
72
+ /**
73
+ * {@inheritDoc}
74
+ */
75
+ @ Override
76
+ public <B , N extends MonadRec <?, N >> SafeT <N , B > lift (MonadRec <B , N > nb ) {
77
+ return liftSafeT ().apply (nb );
78
+ }
79
+
80
+ /**
81
+ * {@inheritDoc}
82
+ */
83
+ @ Override
84
+ public <B > SafeT <M , B > flatMap (Fn1 <? super A , ? extends Monad <B , SafeT <M , ?>>> f ) {
85
+ return new SafeT <>(Body .suspend (body , a -> f .apply (a ).<SafeT <M , B >>coerce ().body ), pureM );
86
+ }
87
+
88
+ /**
89
+ * {@inheritDoc}
90
+ */
91
+ @ Override
92
+ public <B > SafeT <M , B > zip (Applicative <Fn1 <? super A , ? extends B >, SafeT <M , ?>> appFn ) {
93
+ return body .resume ()
94
+ .match (mBodyA -> appFn .<SafeT <M , Fn1 <? super A , ? extends B >>>coerce ().body .resume ()
95
+ .match (mBodyF -> new SafeT <>(Body .more (mBodyA .zip (mBodyF .fmap (
96
+ bodyF -> bodyA -> new SafeT <>(bodyA , pureM ).zip (new SafeT <>(bodyF , pureM )).body ))), pureM ),
97
+ f -> new SafeT <>(Body .more (mBodyA .fmap (b -> Body .suspend (
98
+ b , a -> Body .done (f .apply (a ))))), pureM )),
99
+ a -> appFn .<SafeT <M , Fn1 <? super A , ? extends B >>>coerce ().body .resume ()
100
+ .match (mBodyF -> new SafeT <>(new Body .More <>(mBodyF .fmap (
101
+ body -> new SafeT <>(body , pureM ).<B >fmap (f -> f .apply (a )).body )), pureM ),
102
+ f -> pure (f .apply (a ))));
103
+ }
104
+
105
+ /**
106
+ * {@inheritDoc}
107
+ */
108
+ @ Override
109
+ public <B > Lazy <SafeT <M , B >> lazyZip (
110
+ Lazy <? extends Applicative <Fn1 <? super A , ? extends B >, SafeT <M , ?>>> lazyAppFn ) {
111
+ return MonadT .super .lazyZip (lazyAppFn ).fmap (Applicative <B , SafeT <M , ?>>::coerce );
112
+ }
113
+
114
+ /**
115
+ * {@inheritDoc}
116
+ */
117
+ @ Override
118
+ public <B > SafeT <M , B > discardL (Applicative <B , SafeT <M , ?>> appB ) {
119
+ return MonadT .super .discardL (appB ).coerce ();
120
+ }
121
+
122
+ /**
123
+ * {@inheritDoc}
124
+ */
125
+ @ Override
126
+ public <B > SafeT <M , A > discardR (Applicative <B , SafeT <M , ?>> appB ) {
127
+ return MonadT .super .discardR (appB ).coerce ();
128
+ }
129
+
130
+ /**
131
+ * {@inheritDoc}
132
+ */
133
+ @ Override
134
+ public <B > SafeT <M , B > pure (B b ) {
135
+ return pureSafeT (pureM ).apply (b );
136
+ }
137
+
138
+ /**
139
+ * {@inheritDoc}
140
+ */
141
+ @ Override
142
+ public <B > SafeT <M , B > trampolineM (Fn1 <? super A , ? extends MonadRec <RecursiveResult <A , B >, SafeT <M , ?>>> bounce ) {
143
+ return flatMap (bounce .fmap (mab -> mab .flatMap (aOrB -> aOrB
144
+ .match (a -> mab .pure (a ).trampolineM (bounce ), Pure .of (mab )::apply ))));
145
+ }
146
+
147
+ /**
148
+ * Lift any <code>{@link MonadRec MonadRec}<A, M></code> into a <code>{@link SafeT SafeT}<M, A></code>.
149
+ *
150
+ * @param ma the {@link MonadRec MonadRec}<A, M>
151
+ * @param <M> the {@link MonadRec} witness
152
+ * @param <A> the carrier type
153
+ * @return the new {@link SafeT}
154
+ */
155
+ public static <M extends MonadRec <?, M >, A > SafeT <M , A > safeT (MonadRec <A , M > ma ) {
156
+ return new SafeT <>(new Body .More <>(ma .fmap (Body .Done ::new )), Pure .of (ma ));
157
+ }
158
+
159
+ /**
160
+ * The canonical {@link Pure} instance for {@link SafeT}.
161
+ *
162
+ * @param pureM the argument {@link Monad} {@link Pure}
163
+ * @param <M> the argument {@link Monad} witness
164
+ * @return the {@link Pure} instance
165
+ */
166
+ public static <M extends MonadRec <?, M >> Pure <SafeT <M , ?>> pureSafeT (Pure <M > pureM ) {
167
+ return new Pure <SafeT <M , ?>>() {
168
+ @ Override
169
+ public <A > SafeT <M , A > checkedApply (A a ) throws Throwable {
170
+ return safeT (pureM .<A , MonadRec <A , M >>apply (a ));
171
+ }
172
+ };
173
+ }
174
+
175
+ /**
176
+ * {@link Lift} for {@link SafeT}.
177
+ *
178
+ * @return the {@link Monad} lifted into {@link SafeT}
179
+ */
180
+ public static Lift <SafeT <?, ?>> liftSafeT () {
181
+ return SafeT ::safeT ;
182
+ }
183
+
184
+ private abstract static class Body <M extends MonadRec <?, M >, A > implements
185
+ CoProduct2 <Either <MonadRec <Body <M , A >, M >, A >, Body .Suspended <M , ?, A >, Body <M , A >> {
186
+
187
+ private Body () {
188
+ }
189
+
190
+ public abstract Either <MonadRec <Body <M , A >, M >, A > resume ();
191
+
192
+ private static <M extends MonadRec <?, M >, A > Body <M , A > done (A a ) {
193
+ return new Done <>(a );
194
+ }
195
+
196
+ private static <M extends MonadRec <?, M >, A > Body <M , A > more (MonadRec <Body <M , A >, M > mb ) {
197
+ return new More <>(mb );
198
+ }
199
+
200
+ private static <M extends MonadRec <?, M >, A , B > Body <M , B > suspend (Body <M , A > freeA , Fn1 <A , Body <M , B >> fn ) {
201
+ return new SafeT .Body .Suspended <>(freeA , fn );
202
+ }
203
+
204
+ private static final class Done <M extends MonadRec <?, M >, A > extends Body <M , A > {
205
+ private final A a ;
206
+
207
+ private Done (A a ) {
208
+ this .a = a ;
209
+ }
210
+
211
+ @ Override
212
+ public <R > R match (Fn1 <? super Either <MonadRec <Body <M , A >, M >, A >, ? extends R > aFn ,
213
+ Fn1 <? super SafeT .Body .Suspended <M , ?, A >, ? extends R > bFn ) {
214
+ return aFn .apply (right (a ));
215
+ }
216
+
217
+ @ Override
218
+ public Either <MonadRec <Body <M , A >, M >, A > resume () {
219
+ return right (a );
220
+ }
221
+ }
222
+
223
+ private static final class More <M extends MonadRec <?, M >, A > extends Body <M , A > {
224
+ private final MonadRec <Body <M , A >, M > mfa ;
225
+
226
+ private More (MonadRec <Body <M , A >, M > mfa ) {
227
+ this .mfa = mfa ;
228
+ }
229
+
230
+ @ Override
231
+ public <R > R match (Fn1 <? super Either <MonadRec <Body <M , A >, M >, A >, ? extends R > aFn ,
232
+ Fn1 <? super SafeT .Body .Suspended <M , ?, A >, ? extends R > bFn ) {
233
+ return aFn .apply (left (mfa ));
234
+ }
235
+
236
+ @ Override
237
+ public Either <MonadRec <Body <M , A >, M >, A > resume () {
238
+ return left (mfa );
239
+ }
240
+ }
241
+
242
+ private static final class Suspended <M extends MonadRec <?, M >, A , B > extends Body <M , B > {
243
+ private final Body <M , A > source ;
244
+ private final Fn1 <A , Body <M , B >> f ;
245
+
246
+ private Suspended (Body <M , A > source , Fn1 <A , Body <M , B >> f ) {
247
+ this .source = source ;
248
+ this .f = f ;
249
+ }
250
+
251
+ public Either <MonadRec <Body <M , B >, M >, B > resume () {
252
+ Φ <M , B , RecursiveResult <Body <M , B >, Either <MonadRec <Body <M , B >, M >, B >>> phi =
253
+ new Φ <M , B , RecursiveResult <Body <M , B >, Either <MonadRec <Body <M , B >, M >, B >>>() {
254
+ @ Override
255
+ public <Z > RecursiveResult <Body <M , B >, Either <MonadRec <Body <M , B >, M >, B >> apply (
256
+ Body <M , Z > source , Fn1 <Z , Body <M , B >> f ) {
257
+ return source .match (
258
+ e -> e .match (more -> terminate (left (more .fmap (body -> suspend (body , f )))),
259
+ z -> recurse (f .apply (z ))),
260
+ associateRight (f ));
261
+ }
262
+ };
263
+ return Trampoline .<Body <M , B >, Either <MonadRec <Body <M , B >, M >, B >>trampoline (
264
+ free -> free .match (RecursiveResult ::terminate , suspended -> suspended .eliminate (phi )),
265
+ this );
266
+ }
267
+
268
+ @ Override
269
+ public <R > R match (Fn1 <? super Either <MonadRec <Body <M , B >, M >, B >, ? extends R > aFn ,
270
+ Fn1 <? super Suspended <M , ?, B >, ? extends R > bFn ) {
271
+ return bFn .apply (this );
272
+ }
273
+
274
+ private <Z > Fn1 <Suspended <M , ?, Z >, RecursiveResult <Body <M , B >, Either <MonadRec <Body <M , B >, M >, B >>>
275
+ associateRight (Fn1 <Z , Body <M , B >> f ) {
276
+ Φ <M , Z , RecursiveResult <Body <M , B >, Either <MonadRec <Body <M , B >, M >, B >>> phi =
277
+ new Φ <M , Z , RecursiveResult <Body <M , B >, Either <MonadRec <Body <M , B >, M >, B >>>() {
278
+ @ Override
279
+ public <Y > RecursiveResult <Body <M , B >, Either <MonadRec <Body <M , B >, M >, B >> apply (
280
+ Body <M , Y > source ,
281
+ Fn1 <Y , Body <M , Z >> g ) {
282
+ return recurse (suspend (source , x -> suspend (g .apply (x ), f )));
283
+ }
284
+ };
285
+
286
+ return suspended -> suspended .eliminate (phi );
287
+ }
288
+
289
+ @ SuppressWarnings ("NonAsciiCharacters" )
290
+ private <R > R eliminate (Φ <M , B , R > Φ ) {
291
+ return Φ .apply (source , f );
292
+ }
293
+
294
+ @ SuppressWarnings ("NonAsciiCharacters" )
295
+ private interface Φ <M extends MonadRec <?, M >, B , R > {
296
+ <A > R apply (Body <M , A > source , Fn1 <A , Body <M , B >> fn );
297
+ }
298
+ }
299
+ }
300
+ }
0 commit comments