Skip to content

Commit 8eac39a

Browse files
mrbackendjbgi
authored andcommitted
Stack safe State
1 parent 7b84ad9 commit 8eac39a

2 files changed

Lines changed: 516 additions & 106 deletions

File tree

Lines changed: 107 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,118 +1,119 @@
11
package fj.data;
22

3-
import fj.*;
3+
import fj.F;
4+
import fj.P2;
5+
import fj.Unit;
6+
import fj.control.Trampoline;
47

8+
import static fj.P.lazy;
59
import static fj.P.p;
10+
import static fj.control.Trampoline.suspend;
11+
import static fj.data.List.cons;
612

713
/**
814
* Created by MarkPerry on 7/07/2014.
915
*/
1016
public final class State<S, A> {
1117

12-
private final F<S, P2<S, A>> run;
13-
14-
private State(F<S, P2<S, A>> f) {
15-
run = f;
16-
}
17-
18-
public P2<S, A> run(S s) {
19-
return run.f(s);
20-
}
21-
22-
public static <S, A> State<S, A> unit(F<S, P2<S, A>> f) {
23-
return new State<>(f);
24-
}
25-
26-
public static <S> State<S, S> units(F<S, S> f) {
27-
return unit((S s) -> {
28-
S s2 = f.f(s);
29-
return p(s2, s2);
30-
});
31-
}
32-
33-
public static <S, A> State<S, A> constant(A a) {
34-
return unit(s -> p(s, a));
35-
}
36-
37-
public <B> State<S, B> map(F<A, B> f) {
38-
return unit((S s) -> {
39-
P2<S, A> p2 = run(s);
40-
B b = f.f(p2._2());
41-
return p(p2._1(), b);
42-
});
43-
}
44-
45-
public static <S> State<S, Unit> modify(F<S, S> f) {
46-
return State.<S>init().flatMap(s -> unit(s2 -> p(f.f(s), Unit.unit())));
47-
}
48-
49-
public <B> State<S, B> mapState(F<P2<S, A>, P2<S, B>> f) {
50-
return unit(s -> f.f(run(s)));
51-
}
52-
53-
public static <S, B, C> State<S, C> flatMap(State<S, B> mb, F<B, State<S, C>> f) {
54-
return mb.flatMap(f);
55-
}
56-
57-
public <B> State<S, B> flatMap(F<A, State<S, B>> f) {
58-
return unit((S s) -> {
59-
P2<S, A> p = run(s);
60-
A a = p._2();
61-
S s2 = p._1();
62-
State<S, B> smb = f.f(a);
63-
return smb.run(s2);
64-
});
65-
}
66-
67-
public static <S> State<S, S> init() {
68-
return unit(s -> p(s, s));
69-
}
70-
71-
public State<S, S> gets() {
72-
return unit(s -> {
73-
P2<S, A> p = run(s);
74-
S s2 = p._1();
75-
return p(s2, s2);
76-
});
77-
}
78-
79-
public static <S> State<S, Unit> put(S s) {
80-
return unit((S z) -> p(s, Unit.unit()));
81-
}
82-
83-
public A eval(S s) {
84-
return run(s)._2();
85-
}
86-
87-
public S exec(S s) {
88-
return run(s)._1();
89-
}
90-
91-
public State<S, A> withs(F<S, S> f) {
92-
return unit(F1Functions.andThen(f, run));
93-
}
94-
95-
public static <S, A> State<S, A> gets(F<S, A> f) {
96-
return State.<S>init().map(f);
97-
}
98-
99-
/**
100-
* Evaluate each action in the sequence from left to right, and collect the results.
101-
*/
102-
public static <S, A> State<S, List<A>> sequence(List<State<S, A>> list) {
103-
return list.foldLeft((State<S, List<A>> acc, State<S, A> ma) ->
104-
acc.flatMap((List<A> xs) -> ma.map(xs::snoc)
105-
), constant(List.nil()));
106-
}
107-
108-
/**
109-
* Map each element of a structure to an action, evaluate these actions from left to right
110-
* and collect the results.
111-
*/
112-
public static <S, A, B> State<S, List<B>> traverse(List<A> list, F<A, State<S, B>> f) {
113-
return list.foldLeft((State<S, List<B>> acc, A a) ->
114-
acc.flatMap(bs -> f.f(a).map(bs::snoc)
115-
), constant(List.nil()));
116-
}
18+
public static <S, A> State<S, A> unit(F<S, P2<S, A>> runF) {
19+
return new State<>(s -> Trampoline.pure(runF.f(s)));
20+
}
21+
22+
public static <S> State<S, S> init() {
23+
return unit(s -> dup(s));
24+
}
25+
26+
public static <S> State<S, S> units(F<S, S> f) {
27+
return unit(s -> dup(f.f(s)));
28+
}
29+
30+
private static <S> P2<S, S> dup(S s) {
31+
return p(s, s);
32+
}
33+
34+
public static <S, A> State<S, A> constant(A a) {
35+
return unit(s -> p(s, a));
36+
}
37+
38+
public static <S, A> State<S, A> gets(F<S, A> f) {
39+
return unit(s -> p(s, f.f(s)));
40+
}
41+
42+
public static <S> State<S, Unit> put(S s) {
43+
return unit(ignoredS -> p(s, Unit.unit()));
44+
}
45+
46+
public static <S> State<S, Unit> modify(F<S, S> f) {
47+
return unit(s -> p(f.f(s), Unit.unit()));
48+
}
49+
50+
public static <S, A, B> State<S, B> flatMap(State<S, A> ts, F<A, State<S, B>> f) {
51+
return ts.flatMap(f);
52+
}
53+
54+
/**
55+
* Evaluate each action in the sequence from left to right, and collect the results.
56+
*/
57+
public static <S, A> State<S, List<A>> sequence(List<State<S, A>> list) {
58+
return list
59+
.foldLeft(
60+
(acc, ts) -> acc.flatMap(as -> ts.map(a -> cons(a, as))),
61+
State.<S, List<A>>constant(List.nil()))
62+
.map(as -> as.reverse());
63+
}
64+
65+
/**
66+
* Map each element of a structure to an action, evaluate these actions from left to right
67+
* and collect the results.
68+
*/
69+
public static <S, A, B> State<S, List<B>> traverse(List<A> list, F<A, State<S, B>> f) {
70+
return list
71+
.foldLeft(
72+
(acc, a) -> acc.flatMap(bs -> f.f(a).map(b -> cons(b, bs))),
73+
State.<S, List<B>>constant(List.nil()))
74+
.map(bs -> bs.reverse());
75+
}
76+
77+
private static <S, A> State<S, A> suspended(F<S, Trampoline<P2<S, A>>> runF) {
78+
return new State<>(s -> suspend(lazy(() -> runF.f(s))));
79+
}
80+
81+
private final F<S, Trampoline<P2<S, A>>> runF;
82+
83+
private State(F<S, Trampoline<P2<S, A>>> runF) {
84+
this.runF = runF;
85+
}
86+
87+
public P2<S, A> run(S s) {
88+
return runF.f(s).run();
89+
}
90+
91+
public A eval(S s) {
92+
return run(s)._2();
93+
}
94+
95+
public S exec(S s) {
96+
return run(s)._1();
97+
}
98+
99+
public State<S, S> gets() {
100+
return mapState(result -> p(result._1(), result._1()));
101+
}
102+
103+
public <B> State<S, B> map(F<A, B> f) {
104+
return mapState(result -> p(result._1(), f.f(result._2())));
105+
}
106+
107+
public <B> State<S, B> mapState(F<P2<S, A>, P2<S, B>> f) {
108+
return suspended(s -> runF.f(s).map(result -> f.f(result)));
109+
}
110+
111+
public State<S, A> withs(F<S, S> f) {
112+
return suspended(s -> runF.f(f.f(s)));
113+
}
114+
115+
public <B> State<S, B> flatMap(F<A, State<S, B>> f) {
116+
return suspended(s -> runF.f(s).bind(result -> Trampoline.pure(f.f(result._2()).run(result._1()))));
117+
}
117118

118119
}

0 commit comments

Comments
 (0)