8
8
import com .jnape .palatable .lambda .functor .builtin .Lazy ;
9
9
import com .jnape .palatable .lambda .functor .builtin .Writer ;
10
10
import com .jnape .palatable .lambda .io .IO ;
11
+ import com .jnape .palatable .lambda .monoid .Monoid ;
11
12
import com .jnape .palatable .traitor .annotations .TestTraits ;
12
13
import com .jnape .palatable .traitor .framework .Subjects ;
13
14
import com .jnape .palatable .traitor .runners .Traits ;
14
15
import org .junit .Test ;
15
16
import org .junit .runner .RunWith ;
16
- import testsupport .traits .*;
17
+ import testsupport .traits .ApplicativeLaws ;
18
+ import testsupport .traits .Equivalence ;
19
+ import testsupport .traits .FunctorLaws ;
20
+ import testsupport .traits .MonadLaws ;
21
+ import testsupport .traits .MonadRecLaws ;
17
22
18
23
import java .util .ArrayList ;
19
24
import java .util .Collection ;
20
25
import java .util .List ;
21
26
import java .util .concurrent .CountDownLatch ;
27
+ import java .util .concurrent .atomic .AtomicInteger ;
22
28
23
29
import static com .jnape .palatable .lambda .adt .Maybe .just ;
24
30
import static com .jnape .palatable .lambda .adt .Maybe .nothing ;
25
31
import static com .jnape .palatable .lambda .adt .Unit .UNIT ;
26
32
import static com .jnape .palatable .lambda .adt .hlist .HList .tuple ;
33
+ import static com .jnape .palatable .lambda .functions .builtin .fn1 .Constantly .constantly ;
27
34
import static com .jnape .palatable .lambda .functions .builtin .fn2 .LTE .lte ;
28
35
import static com .jnape .palatable .lambda .functions .builtin .fn3 .Times .times ;
29
36
import static com .jnape .palatable .lambda .functions .recursion .RecursiveResult .recurse ;
30
37
import static com .jnape .palatable .lambda .functions .recursion .RecursiveResult .terminate ;
31
38
import static com .jnape .palatable .lambda .functor .builtin .Identity .pureIdentity ;
32
39
import static com .jnape .palatable .lambda .functor .builtin .Lazy .lazy ;
33
- import static com .jnape .palatable .lambda .functor .builtin .Writer .*;
40
+ import static com .jnape .palatable .lambda .functor .builtin .Writer .listen ;
41
+ import static com .jnape .palatable .lambda .functor .builtin .Writer .pureWriter ;
42
+ import static com .jnape .palatable .lambda .functor .builtin .Writer .tell ;
43
+ import static com .jnape .palatable .lambda .functor .builtin .Writer .writer ;
34
44
import static com .jnape .palatable .lambda .io .IO .io ;
35
- import static com .jnape .palatable .lambda .monad .transformer .builtin .IterateT .*;
45
+ import static com .jnape .palatable .lambda .monad .transformer .builtin .IterateT .empty ;
46
+ import static com .jnape .palatable .lambda .monad .transformer .builtin .IterateT .iterateT ;
47
+ import static com .jnape .palatable .lambda .monad .transformer .builtin .IterateT .liftIterateT ;
48
+ import static com .jnape .palatable .lambda .monad .transformer .builtin .IterateT .of ;
49
+ import static com .jnape .palatable .lambda .monad .transformer .builtin .IterateT .pureIterateT ;
50
+ import static com .jnape .palatable .lambda .monad .transformer .builtin .IterateT .singleton ;
51
+ import static com .jnape .palatable .lambda .monad .transformer .builtin .IterateT .unfold ;
36
52
import static com .jnape .palatable .lambda .monoid .builtin .AddAll .addAll ;
37
53
import static com .jnape .palatable .lambda .monoid .builtin .Join .join ;
38
54
import static com .jnape .palatable .traitor .framework .Subjects .subjects ;
44
60
import static org .junit .Assert .assertThat ;
45
61
import static testsupport .Constants .STACK_EXPLODING_NUMBER ;
46
62
import static testsupport .matchers .IOMatcher .yieldsValue ;
47
- import static testsupport .matchers .IterateTMatcher .*;
63
+ import static testsupport .matchers .IterateTMatcher .isEmpty ;
64
+ import static testsupport .matchers .IterateTMatcher .iterates ;
65
+ import static testsupport .matchers .IterateTMatcher .iteratesAll ;
48
66
import static testsupport .traits .Equivalence .equivalence ;
49
67
50
68
@ RunWith (Traits .class )
@@ -236,16 +254,16 @@ public void concatIsStackSafe() {
236
254
public void staticPure () {
237
255
assertEquals (new Identity <>(singletonList (1 )),
238
256
pureIterateT (pureIdentity ())
239
- .<Integer , IterateT <Identity <?>, Integer >>apply (1 )
240
- .<List <Integer >, Identity <List <Integer >>>toCollection (ArrayList ::new ));
257
+ .<Integer , IterateT <Identity <?>, Integer >>apply (1 )
258
+ .<List <Integer >, Identity <List <Integer >>>toCollection (ArrayList ::new ));
241
259
}
242
260
243
261
@ Test
244
262
public void staticLift () {
245
263
assertEquals (new Identity <>(singletonList (1 )),
246
264
liftIterateT ()
247
- .<Integer , Identity <?>, IterateT <Identity <?>, Integer >>apply (new Identity <>(1 ))
248
- .<List <Integer >, Identity <List <Integer >>>toCollection (ArrayList ::new ));
265
+ .<Integer , Identity <?>, IterateT <Identity <?>, Integer >>apply (new Identity <>(1 ))
266
+ .<List <Integer >, Identity <List <Integer >>>toCollection (ArrayList ::new ));
249
267
}
250
268
251
269
@ Test
@@ -257,4 +275,42 @@ public void trampolineMRecursesBreadth() {
257
275
: singleton (new Identity <>(terminate (x ))));
258
276
assertThat (trampolined , iterates (1 , 2 , 13 , 14 , 25 , 26 , 37 , 38 , 39 , 40 , 28 , 16 , 4 ));
259
277
}
278
+
279
+ @ Test
280
+ public void flatMapToEmptyStackSafety () {
281
+ assertEquals (new Identity <>(UNIT ),
282
+ unfold (x -> new Identity <>(x <= STACK_EXPLODING_NUMBER ? just (tuple (x , x + 1 )) : nothing ()),
283
+ new Identity <>(1 ))
284
+ .flatMap (constantly (iterateT (new Identity <>(nothing ()))))
285
+ .forEach (constantly (new Identity <>(UNIT ))));
286
+
287
+ assertEquals ((Integer ) 1_250_025_000 ,
288
+ unfold (x -> listen (x <= STACK_EXPLODING_NUMBER ? just (tuple (x , x + 1 )) : nothing ()),
289
+ Writer .<Integer , Integer >listen (1 ))
290
+ .flatMap (x -> iterateT (writer (tuple (nothing (), x ))))
291
+ .<Writer <Integer , Unit >>forEach (constantly (listen (UNIT )))
292
+ .runWriter (Monoid .monoid (Integer ::sum , 0 ))
293
+ ._2 ());
294
+ }
295
+
296
+ @ Test
297
+ public void flatMapCostsNoMoreEffortThanRequiredToYieldFirstValue () {
298
+ AtomicInteger flatMapCost = new AtomicInteger (0 );
299
+ AtomicInteger unfoldCost = new AtomicInteger (0 );
300
+ assertEquals (just (1 ),
301
+ unfold (x -> {
302
+ unfoldCost .incrementAndGet ();
303
+ return new Identity <>(x <= 10 ? just (tuple (x , x + 1 )) : nothing ());
304
+ },
305
+ new Identity <>(1 ))
306
+ .flatMap (x -> {
307
+ flatMapCost .incrementAndGet ();
308
+ return singleton (new Identity <>(x ));
309
+ })
310
+ .<Identity <Maybe <Tuple2 <Integer , IterateT <Identity <?>, Integer >>>>>runIterateT ()
311
+ .runIdentity ()
312
+ .fmap (Tuple2 ::_1 ));
313
+ assertEquals (1 , flatMapCost .get ());
314
+ assertEquals (1 , unfoldCost .get ());
315
+ }
260
316
}
0 commit comments