forked from functionaljava/functionaljava
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathState.java
More file actions
119 lines (93 loc) · 2.92 KB
/
State.java
File metadata and controls
119 lines (93 loc) · 2.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package fj.data;
import fj.F;
import fj.P2;
import fj.Unit;
import fj.control.Trampoline;
import static fj.P.lazy;
import static fj.P.p;
import static fj.control.Trampoline.suspend;
import static fj.data.List.cons;
/**
* Created by MarkPerry on 7/07/2014.
*/
public final class State<S, A> {
public static <S, A> State<S, A> unit(F<S, P2<S, A>> runF) {
return new State<>(s -> Trampoline.pure(runF.f(s)));
}
public static <S> State<S, S> init() {
return unit(s -> dup(s));
}
public static <S> State<S, S> units(F<S, S> f) {
return unit(s -> dup(f.f(s)));
}
private static <S> P2<S, S> dup(S s) {
return p(s, s);
}
public static <S, A> State<S, A> constant(A a) {
return unit(s -> p(s, a));
}
public static <S, A> State<S, A> gets(F<S, A> f) {
return unit(s -> p(s, f.f(s)));
}
public static <S> State<S, Unit> put(S s) {
return unit(ignoredS -> p(s, Unit.unit()));
}
public static <S> State<S, Unit> modify(F<S, S> f) {
return unit(s -> p(f.f(s), Unit.unit()));
}
public static <S, A, B> State<S, B> flatMap(State<S, A> ts, F<A, State<S, B>> f) {
return ts.flatMap(f);
}
/**
* Evaluate each action in the sequence from left to right, and collect the results.
*/
public static <S, A> State<S, List<A>> sequence(List<State<S, A>> list) {
return list
.foldLeft(
(acc, ts) -> acc.flatMap(as -> ts.map(a -> cons(a, as))),
State.<S, List<A>>constant(List.nil()))
.map(as -> as.reverse());
}
/**
* Map each element of a structure to an action, evaluate these actions from left to right
* and collect the results.
*/
public static <S, A, B> State<S, List<B>> traverse(List<A> list, F<A, State<S, B>> f) {
return list
.foldLeft(
(acc, a) -> acc.flatMap(bs -> f.f(a).map(b -> cons(b, bs))),
State.<S, List<B>>constant(List.nil()))
.map(bs -> bs.reverse());
}
private static <S, A> State<S, A> suspended(F<S, Trampoline<P2<S, A>>> runF) {
return new State<>(s -> suspend(lazy(() -> runF.f(s))));
}
private final F<S, Trampoline<P2<S, A>>> runF;
private State(F<S, Trampoline<P2<S, A>>> runF) {
this.runF = runF;
}
public P2<S, A> run(S s) {
return runF.f(s).run();
}
public A eval(S s) {
return run(s)._2();
}
public S exec(S s) {
return run(s)._1();
}
public State<S, S> gets() {
return mapState(result -> p(result._1(), result._1()));
}
public <B> State<S, B> map(F<A, B> f) {
return mapState(result -> p(result._1(), f.f(result._2())));
}
public <B> State<S, B> mapState(F<P2<S, A>, P2<S, B>> f) {
return suspended(s -> runF.f(s).map(result -> f.f(result)));
}
public State<S, A> withs(F<S, S> f) {
return suspended(s -> runF.f(f.f(s)));
}
public <B> State<S, B> flatMap(F<A, State<S, B>> f) {
return suspended(s -> runF.f(s).bind(result -> Trampoline.pure(f.f(result._2()).run(result._1()))));
}
}