Skip to content

Commit d3a049c

Browse files
committed
ReaderT#fmap and StateT#fmap don't unnecessarily rely on pure
1 parent 3f23529 commit d3a049c

File tree

5 files changed

+36
-3
lines changed

5 files changed

+36
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
77

88
### Changed
99
- `IterateT#unfold` now only computes a single `Pure` for the given input
10+
- `ReaderT#fmap` and `StateT#fmap` avoid unnecessary calls to `pure`
1011

1112
### Added
1213
- `$`, function application represented as a higher-order `Fn2`

src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public <B> ReaderT<R, M, B> pure(B b) {
120120
*/
121121
@Override
122122
public <B> ReaderT<R, M, B> fmap(Fn1<? super A, ? extends B> fn) {
123-
return MonadT.super.<B>fmap(fn).coerce();
123+
return readerT(r -> runReaderT(r).fmap(fn));
124124
}
125125

126126
/**

src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ public <B> StateT<S, M, B> pure(B b) {
144144
*/
145145
@Override
146146
public <B> StateT<S, M, B> fmap(Fn1<? super A, ? extends B> fn) {
147-
return MonadT.super.<B>fmap(fn).coerce();
147+
return stateT(s -> runStateT(s).fmap(t -> t.biMapL(fn)));
148148
}
149149

150150
/**
@@ -292,7 +292,7 @@ public static <S, M extends MonadRec<?, M>, A> StateT<S, M, A> stateT(
292292
public static <S, M extends MonadRec<?, M>> Pure<StateT<S, M, ?>> pureStateT(Pure<M> pureM) {
293293
return new Pure<StateT<S, M, ?>>() {
294294
@Override
295-
public <A> StateT<S, M, A> checkedApply(A a) throws Throwable {
295+
public <A> StateT<S, M, A> checkedApply(A a) {
296296
return stateT(pureM.<A, MonadRec<A, M>>apply(a));
297297
}
298298
};

src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.jnape.palatable.lambda.adt.Maybe;
44
import com.jnape.palatable.lambda.adt.Unit;
5+
import com.jnape.palatable.lambda.functions.Fn1;
56
import com.jnape.palatable.lambda.functor.builtin.Identity;
67
import com.jnape.palatable.lambda.io.IO;
78
import com.jnape.palatable.traitor.annotations.TestTraits;
@@ -12,6 +13,7 @@
1213

1314
import java.util.concurrent.CountDownLatch;
1415
import java.util.concurrent.Executors;
16+
import java.util.concurrent.atomic.AtomicInteger;
1517

1618
import static com.jnape.palatable.lambda.adt.Maybe.just;
1719
import static com.jnape.palatable.lambda.adt.Unit.UNIT;
@@ -82,4 +84,17 @@ public void composedZip() {
8284
.unsafePerformAsyncIO(Executors.newFixedThreadPool(2))
8385
.join();
8486
}
87+
88+
@Test
89+
public void fmapInteractions() {
90+
AtomicInteger invocations = new AtomicInteger(0);
91+
ReaderT<Integer, Identity<?>, Integer> readerT = readerT(i -> {
92+
invocations.incrementAndGet();
93+
return new Identity<>(i);
94+
});
95+
96+
Fn1<Integer, Integer> plusOne = x -> x + 1;
97+
readerT.fmap(plusOne).fmap(plusOne).fmap(plusOne).runReaderT(0);
98+
assertEquals(1, invocations.get());
99+
}
85100
}

src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@
1616

1717
import java.util.ArrayList;
1818
import java.util.List;
19+
import java.util.concurrent.atomic.AtomicInteger;
1920

2021
import static com.jnape.palatable.lambda.adt.Maybe.just;
2122
import static com.jnape.palatable.lambda.adt.Unit.UNIT;
2223
import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
24+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id;
2325
import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity;
2426
import static com.jnape.palatable.lambda.optics.functions.Set.set;
2527
import static com.jnape.palatable.lambda.optics.lenses.ListLens.elementAt;
2628
import static java.util.Arrays.asList;
2729
import static org.hamcrest.MatcherAssert.assertThat;
30+
import static org.junit.Assert.assertEquals;
2831
import static testsupport.matchers.StateTMatcher.whenEvaluated;
2932
import static testsupport.matchers.StateTMatcher.whenExecuted;
3033
import static testsupport.matchers.StateTMatcher.whenRun;
@@ -119,4 +122,18 @@ public void staticLift() {
119122
assertThat(StateT.<String>liftStateT().apply(new Identity<>(1)),
120123
whenRun("foo", new Identity<>(tuple(1, "foo"))));
121124
}
125+
126+
@Test
127+
public void fmapInteractions() {
128+
AtomicInteger invocations = new AtomicInteger(0);
129+
StateT.<Integer, Identity<?>, Integer>gets(x -> {
130+
invocations.incrementAndGet();
131+
return new Identity<>(x);
132+
})
133+
.fmap(id())
134+
.fmap(id())
135+
.fmap(id())
136+
.<Identity<Tuple2<Integer, Integer>>>runStateT(0);
137+
assertEquals(1, invocations.get());
138+
}
122139
}

0 commit comments

Comments
 (0)