|
1 | 1 | package fj.data; |
2 | 2 |
|
3 | | -import fj.*; |
| 3 | +import fj.F; |
| 4 | +import fj.P2; |
| 5 | +import fj.Unit; |
| 6 | +import fj.control.Trampoline; |
4 | 7 |
|
| 8 | +import static fj.P.lazy; |
5 | 9 | import static fj.P.p; |
| 10 | +import static fj.control.Trampoline.suspend; |
| 11 | +import static fj.data.List.cons; |
6 | 12 |
|
7 | 13 | /** |
8 | 14 | * Created by MarkPerry on 7/07/2014. |
9 | 15 | */ |
10 | 16 | public final class State<S, A> { |
11 | 17 |
|
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 | + } |
117 | 118 |
|
118 | 119 | } |
0 commit comments