Skip to content

Commit 23bf1e9

Browse files
committed
Writer and State more directly rely on identity transformers
1 parent c568c22 commit 23bf1e9

File tree

5 files changed

+95
-54
lines changed

5 files changed

+95
-54
lines changed

src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,8 @@
1212
import com.jnape.palatable.lambda.monad.MonadWriter;
1313
import com.jnape.palatable.lambda.monad.transformer.builtin.StateT;
1414

15-
import static com.jnape.palatable.lambda.adt.Unit.UNIT;
16-
import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
17-
import static com.jnape.palatable.lambda.functions.Fn1.fn1;
18-
import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
19-
import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id;
20-
import static com.jnape.palatable.lambda.functions.builtin.fn2.Both.both;
21-
import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into;
22-
import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline;
2315
import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity;
16+
import static com.jnape.palatable.lambda.monad.transformer.builtin.StateT.pureStateT;
2417
import static com.jnape.palatable.lambda.monad.transformer.builtin.StateT.stateT;
2518

2619
/**
@@ -37,10 +30,19 @@ public final class State<S, A> implements
3730
MonadReader<S, A, State<S, ?>>,
3831
MonadWriter<S, A, State<S, ?>> {
3932

40-
private final StateT<S, Identity<?>, A> stateFn;
33+
private final StateT<S, Identity<?>, A> delegate;
4134

42-
private State(StateT<S, Identity<?>, A> stateFn) {
43-
this.stateFn = stateFn;
35+
private State(StateT<S, Identity<?>, A> delegate) {
36+
this.delegate = delegate;
37+
}
38+
39+
/**
40+
* Convert this {@link State} to a {@link StateT} with an {@link Identity} embedding.
41+
*
42+
* @return the {@link StateT}
43+
*/
44+
public StateT<S, Identity<?>, A> toStateT() {
45+
return delegate;
4446
}
4547

4648
/**
@@ -50,7 +52,7 @@ private State(StateT<S, Identity<?>, A> stateFn) {
5052
* @return a {@link Tuple2} of the result and the final state.
5153
*/
5254
public Tuple2<A, S> run(S s) {
53-
return stateFn.<Identity<Tuple2<A, S>>>runStateT(s).runIdentity();
55+
return delegate.<Identity<Tuple2<A, S>>>runStateT(s).runIdentity();
5456
}
5557

5658
/**
@@ -81,7 +83,7 @@ public S exec(S s) {
8183
* @return the mapped {@link State}
8284
*/
8385
public <B> State<S, B> mapState(Fn1<? super Tuple2<A, S>, ? extends Tuple2<B, S>> fn) {
84-
return state(s -> fn.apply(run(s)));
86+
return state(delegate.mapStateT(f -> f.fmap(fn), pureIdentity()));
8587
}
8688

8789
/**
@@ -91,23 +93,23 @@ public <B> State<S, B> mapState(Fn1<? super Tuple2<A, S>, ? extends Tuple2<B, S>
9193
* @return the mapped {@link State}
9294
*/
9395
public State<S, A> withState(Fn1<? super S, ? extends S> fn) {
94-
return state(s -> run(fn.apply(s)));
96+
return state(delegate.withStateT(fn.fmap(Identity::new)));
9597
}
9698

9799
/**
98100
* {@inheritDoc}
99101
*/
100102
@Override
101103
public State<S, A> local(Fn1<? super S, ? extends S> fn) {
102-
return state(s -> run(fn.apply(s)));
104+
return state(delegate.local(fn));
103105
}
104106

105107
/**
106108
* {@inheritDoc}
107109
*/
108110
@Override
109111
public <B> State<S, Tuple2<A, B>> listens(Fn1<? super S, ? extends B> fn) {
110-
return state(s -> run(s).biMapL(both(id(), constantly(fn.apply(s)))));
112+
return state(delegate.listens(fn));
111113
}
112114

113115
/**
@@ -123,15 +125,15 @@ public State<S, A> censor(Fn1<? super S, ? extends S> fn) {
123125
*/
124126
@Override
125127
public <B> State<S, B> flatMap(Fn1<? super A, ? extends Monad<B, State<S, ?>>> f) {
126-
return state(s -> run(s).into((a, s2) -> f.apply(a).<State<S, B>>coerce().run(s2)));
128+
return state(delegate.flatMap(f.fmap(state -> state.<State<S, B>>coerce().delegate)));
127129
}
128130

129131
/**
130132
* {@inheritDoc}
131133
*/
132134
@Override
133135
public <B> State<S, B> pure(B b) {
134-
return state(s -> tuple(b, s));
136+
return state(delegate.pure(b));
135137
}
136138

137139
/**
@@ -180,9 +182,7 @@ public <B> State<S, B> discardL(Applicative<B, State<S, ?>> appB) {
180182
*/
181183
@Override
182184
public <B> State<S, B> trampolineM(Fn1<? super A, ? extends MonadRec<RecursiveResult<A, B>, State<S, ?>>> fn) {
183-
return state(fn1(this::run).fmap(trampoline(into((a, s) -> fn.apply(a)
184-
.<State<S, RecursiveResult<A, B>>>coerce().run(s)
185-
.into((aOrB, s_) -> aOrB.biMap(a_ -> tuple(a_, s_), b -> tuple(b, s_)))))));
185+
return state(delegate.trampolineM(a -> fn.apply(a).<State<S, RecursiveResult<A, B>>>coerce().delegate));
186186
}
187187

188188
/**
@@ -191,9 +191,8 @@ public <B> State<S, B> trampolineM(Fn1<? super A, ? extends MonadRec<RecursiveRe
191191
* @param <A> the state and result type
192192
* @return the new {@link State} instance
193193
*/
194-
@SuppressWarnings("RedundantTypeArguments")
195194
public static <A> State<A, A> get() {
196-
return state(Tuple2::<A>fill);
195+
return state(StateT.get(pureIdentity()));
197196
}
198197

199198
/**
@@ -205,7 +204,7 @@ public static <A> State<A, A> get() {
205204
* @return the new {@link State} instance
206205
*/
207206
public static <S> State<S, Unit> put(S s) {
208-
return modify(constantly(s));
207+
return state(StateT.put(new Identity<>(s)));
209208
}
210209

211210
/**
@@ -217,7 +216,7 @@ public static <S> State<S, Unit> put(S s) {
217216
* @return the new {@link State} instance
218217
*/
219218
public static <S, A> State<S, A> gets(Fn1<? super S, ? extends A> fn) {
220-
return state(both(fn, id()));
219+
return state(StateT.gets(a -> new Identity<>(fn.apply(a)), pureIdentity()));
221220
}
222221

223222
/**
@@ -228,7 +227,7 @@ public static <S, A> State<S, A> gets(Fn1<? super S, ? extends A> fn) {
228227
* @return the new {@link State} instance
229228
*/
230229
public static <S> State<S, Unit> modify(Fn1<? super S, ? extends S> fn) {
231-
return state(both(constantly(UNIT), fn));
230+
return state(StateT.modify(s -> new Identity<>(fn.apply(s)), pureIdentity()));
232231
}
233232

234233
/**
@@ -240,7 +239,7 @@ public static <S> State<S, Unit> modify(Fn1<? super S, ? extends S> fn) {
240239
* @return the new {@link State} instance
241240
*/
242241
public static <S, A> State<S, A> state(A a) {
243-
return gets(constantly(a));
242+
return state(stateT(new Identity<>(a)));
244243
}
245244

246245
/**
@@ -253,7 +252,7 @@ public static <S, A> State<S, A> state(A a) {
253252
* @return the new {@link State} instance
254253
*/
255254
public static <S, A> State<S, A> state(Fn1<? super S, ? extends Tuple2<A, S>> stateFn) {
256-
return new State<>(stateT(s -> new Identity<>(stateFn.apply(s)), pureIdentity()));
255+
return state(stateT(s -> new Identity<>(stateFn.apply(s)), pureIdentity()));
257256
}
258257

259258
/**
@@ -263,11 +262,24 @@ public static <S, A> State<S, A> state(Fn1<? super S, ? extends Tuple2<A, S>> st
263262
* @return the {@link Pure} instance
264263
*/
265264
public static <S> Pure<State<S, ?>> pureState() {
265+
Pure<StateT<S, Identity<?>, ?>> pureStateT = pureStateT(pureIdentity());
266266
return new Pure<State<S, ?>>() {
267267
@Override
268268
public <A> State<S, A> checkedApply(A a) {
269-
return state(s -> tuple(a, s));
269+
return state(pureStateT.<A, StateT<S, Identity<?>, A>>apply(a));
270270
}
271271
};
272272
}
273+
274+
/**
275+
* Create a {@link State} from a delegate {@link StateT} with an {@link Identity} embedding.
276+
*
277+
* @param stateT the delegate {@link StateT}
278+
* @param <S> the state type
279+
* @param <A> the result type
280+
* @return the new {@link State}
281+
*/
282+
public static <S, A> State<S, A> state(StateT<S, Identity<?>, A> stateT) {
283+
return new State<>(stateT);
284+
}
273285
}

src/main/java/com/jnape/palatable/lambda/functor/builtin/Writer.java

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,9 @@
1212
import com.jnape.palatable.lambda.monad.transformer.builtin.WriterT;
1313
import com.jnape.palatable.lambda.monoid.Monoid;
1414

15-
import static com.jnape.palatable.lambda.adt.Unit.UNIT;
16-
import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
17-
import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
18-
import static com.jnape.palatable.lambda.functions.builtin.fn2.Both.both;
19-
import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into;
20-
import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline;
15+
import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity;
16+
import static com.jnape.palatable.lambda.monad.transformer.builtin.WriterT.pureWriterT;
17+
import static com.jnape.palatable.lambda.monad.transformer.builtin.WriterT.writerT;
2118

2219
/**
2320
* The lazy writer monad, a monad capturing some accumulation (eventually to be folded in terms of a given monoid) and
@@ -31,10 +28,19 @@ public final class Writer<W, A> implements
3128
MonadWriter<W, A, Writer<W, ?>>,
3229
MonadRec<A, Writer<W, ?>> {
3330

34-
private final Fn1<? super Monoid<W>, ? extends Tuple2<A, W>> writerFn;
31+
private final WriterT<W, Identity<?>, A> delegate;
3532

36-
private Writer(Fn1<? super Monoid<W>, ? extends Tuple2<A, W>> writerFn) {
37-
this.writerFn = writerFn;
33+
private Writer(WriterT<W, Identity<?>, A> delegate) {
34+
this.delegate = delegate;
35+
}
36+
37+
/**
38+
* Convert this {@link Writer} to a {@link WriterT} with an {@link Identity} embedding.
39+
*
40+
* @return the {@link WriterT}
41+
*/
42+
public WriterT<W, Identity<?>, A> toWriterT() {
43+
return delegate;
3844
}
3945

4046
/**
@@ -45,43 +51,39 @@ private Writer(Fn1<? super Monoid<W>, ? extends Tuple2<A, W>> writerFn) {
4551
* @return the accumulation with the value
4652
*/
4753
public Tuple2<A, W> runWriter(Monoid<W> monoid) {
48-
return writerFn.apply(monoid);
54+
return delegate.<Identity<Tuple2<A, W>>>runWriterT(monoid).runIdentity();
4955
}
5056

5157
/**
5258
* {@inheritDoc}
5359
*/
5460
@Override
5561
public <B> Writer<W, Tuple2<A, B>> listens(Fn1<? super W, ? extends B> fn) {
56-
return new Writer<>(monoid -> runWriter(monoid).into((a, w) -> tuple(both(constantly(a), fn, w), w)));
62+
return new Writer<>(delegate.listens(fn));
5763
}
5864

5965
/**
6066
* {@inheritDoc}
6167
*/
6268
@Override
6369
public Writer<W, A> censor(Fn1<? super W, ? extends W> fn) {
64-
return new Writer<>(monoid -> runWriter(monoid).fmap(fn));
70+
return new Writer<>(delegate.censor(fn));
6571
}
6672

6773
/**
6874
* {@inheritDoc}
6975
*/
7076
@Override
7177
public <B> Writer<W, B> trampolineM(Fn1<? super A, ? extends MonadRec<RecursiveResult<A, B>, Writer<W, ?>>> fn) {
72-
return new Writer<>(monoid -> trampoline(into((a, w) -> fn.apply(a).<Writer<W, RecursiveResult<A, B>>>coerce()
73-
.runWriter(monoid)
74-
.fmap(monoid.apply(w))
75-
.into((aOrB, w_) -> aOrB.biMap(a_ -> tuple(a_, w_), b -> tuple(b, w_)))), runWriter(monoid)));
78+
return new Writer<>(delegate.trampolineM(a -> fn.apply(a).<Writer<W, RecursiveResult<A, B>>>coerce().delegate));
7679
}
7780

7881
/**
7982
* {@inheritDoc}
8083
*/
8184
@Override
8285
public <B> Writer<W, B> flatMap(Fn1<? super A, ? extends Monad<B, Writer<W, ?>>> f) {
83-
return new Writer<>(monoid -> writerFn.apply(monoid)
84-
.into((a, w) -> f.apply(a).<Writer<W, B>>coerce().runWriter(monoid).fmap(monoid.apply(w))));
86+
return new Writer<>(delegate.flatMap(f.fmap(writer -> writer.<Writer<W, B>>coerce().delegate)));
8587
}
8688

8789
/**
@@ -141,7 +143,7 @@ public <B> Writer<W, A> discardR(Applicative<B, Writer<W, ?>> appB) {
141143
* @return the {@link Writer}
142144
*/
143145
public static <W> Writer<W, Unit> tell(W w) {
144-
return writer(tuple(UNIT, w));
146+
return new Writer<>(WriterT.tell(new Identity<>(w)));
145147
}
146148

147149
/**
@@ -153,7 +155,7 @@ public static <W> Writer<W, Unit> tell(W w) {
153155
* @return the {@link Writer}
154156
*/
155157
public static <W, A> Writer<W, A> listen(A a) {
156-
return Writer.<W>pureWriter().apply(a);
158+
return new Writer<>(WriterT.listen(new Identity<>(a)));
157159
}
158160

159161
/**
@@ -162,10 +164,10 @@ public static <W, A> Writer<W, A> listen(A a) {
162164
* @param aw the output value and accumulation
163165
* @param <W> the accumulation type
164166
* @param <A> the value type
165-
* @return the {@link WriterT}
167+
* @return the {@link Writer}
166168
*/
167169
public static <W, A> Writer<W, A> writer(Tuple2<A, W> aw) {
168-
return new Writer<>(constantly(aw));
170+
return new Writer<>(writerT(new Identity<>(aw)));
169171
}
170172

171173
/**
@@ -175,11 +177,24 @@ public static <W, A> Writer<W, A> writer(Tuple2<A, W> aw) {
175177
* @return the {@link Pure} instance
176178
*/
177179
public static <W> Pure<Writer<W, ?>> pureWriter() {
180+
Pure<WriterT<W, Identity<?>, ?>> pureWriterT = pureWriterT(pureIdentity());
178181
return new Pure<Writer<W, ?>>() {
179182
@Override
180183
public <A> Writer<W, A> checkedApply(A a) {
181-
return new Writer<>(monoid -> tuple(a, monoid.identity()));
184+
return new Writer<>(pureWriterT.<A, WriterT<W, Identity<?>, A>>apply(a));
182185
}
183186
};
184187
}
188+
189+
/**
190+
* Create a {@link Writer} from a delegate {@link WriterT} with an {@link Identity} embedding.
191+
*
192+
* @param writerT the delegate {@link WriterT}
193+
* @param <W> the accumulation type
194+
* @param <A> the value type
195+
* @return the {@link Writer}
196+
*/
197+
public static <W, A> Writer<W, A> writer(WriterT<W, Identity<?>, A> writerT) {
198+
return new Writer<>(writerT);
199+
}
185200
}

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
@@ -86,8 +86,8 @@ public <MS extends Monad<S, M>> MS execT(S s) {
8686
* @param <B> the new state type
8787
* @return the mapped {@link StateT}
8888
*/
89-
public <N extends MonadRec<?, N>, B> StateT<S, N, B> mapStateT(
90-
Fn1<? super MonadRec<Tuple2<A, S>, M>, ? extends MonadRec<Tuple2<B, S>, N>> fn, Pure<N> pureN) {
89+
public <MAS extends MonadRec<Tuple2<A, S>, M>, N extends MonadRec<?, N>, B> StateT<S, N, B> mapStateT(
90+
Fn1<? super MAS, ? extends MonadRec<Tuple2<B, S>, N>> fn, Pure<N> pureN) {
9191
return stateT(s -> fn.apply(runStateT(s)), pureN);
9292
}
9393

src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static testsupport.matchers.StateMatcher.whenEvaluated;
2121
import static testsupport.matchers.StateMatcher.whenExecuted;
2222
import static testsupport.matchers.StateMatcher.whenRun;
23+
import static testsupport.matchers.StateTMatcher.whenRun;
2324
import static testsupport.traits.Equivalence.equivalence;
2425

2526
@RunWith(Traits.class)
@@ -35,6 +36,11 @@ public Equivalence<State<String, Integer>> testSubject() {
3536
return equivalence(State.gets(String::length), s -> s.run("foo"));
3637
}
3738

39+
@Test
40+
public void toStateT() {
41+
assertThat(State.<String>get().toStateT(), whenRun("foo", new Identity<>(tuple("foo", "foo"))));
42+
}
43+
3844
@Test
3945
public void eval() {
4046
assertThat(State.gets(id()), whenEvaluated(1, 1));

src/test/java/com/jnape/palatable/lambda/functor/builtin/WriterTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919
import static com.jnape.palatable.lambda.functor.builtin.Writer.writer;
2020
import static com.jnape.palatable.lambda.monoid.builtin.Join.join;
2121
import static com.jnape.palatable.traitor.framework.Subjects.subjects;
22+
import static org.hamcrest.CoreMatchers.equalTo;
2223
import static org.junit.Assert.assertEquals;
24+
import static org.junit.Assert.assertThat;
25+
import static testsupport.matchers.WriterTMatcher.whenRunWith;
2326
import static testsupport.traits.Equivalence.equivalence;
2427

2528
@RunWith(Traits.class)
@@ -33,6 +36,11 @@ public class WriterTest {
3336
equivalence(writer(tuple(1, "foo")), runWriter));
3437
}
3538

39+
@Test
40+
public void toWriterT() {
41+
assertThat(writer(tuple(1, "foo")).toWriterT(), whenRunWith(join(), equalTo(new Identity<>(tuple(1, "foo")))));
42+
}
43+
3644
@Test
3745
public void tellListenInteraction() {
3846
assertEquals(tuple(1, "hello, world!"),

0 commit comments

Comments
 (0)