-
-
Notifications
You must be signed in to change notification settings - Fork 57
/
PolEffectSystem.java
169 lines (133 loc) · 4.58 KB
/
PolEffectSystem.java
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package effects;
import io.vavr.control.Option;
import io.vavr.control.Try;
import org.junit.Test;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* Example of implementation of Monad type in Java
*/
public class PolEffectSystem {
@Test
public void polMonadEffects() {
new PolMonad<String>().pure("hello Pol Monad")
.map(String::toUpperCase)
.flatMap(value -> new PolMonad<>(value + " with composition"))
.forEach(System.out::println);
}
@Test
public void polMonadFromOption() {
new PolMonad<String>().fromOption(Option.of("hello option world"))
.map(String::toUpperCase)
.flatMap(value -> new PolMonad<>(value + " with composition"))
.forEach(System.out::println);
}
@Test
public void polMonadFromTry() {
new PolMonad<String>().fromTry(Try.of(()-> "hello try world"))
.map(String::toUpperCase)
.flatMap(value -> new PolMonad<>(value + " with composition"))
.forEach(System.out::println);
}
@Test
public void polMonadCurried() {
new PolMonad<String>().pure("hello Pol CurriedMonad")
.curried(input -> input2 -> input + input2)
.map(curriedFunc -> curriedFunc.apply(" world"))
.flatMap(value -> new PolMonad<>(value + " with composition"))
.forEach(System.out::println);
}
/**
* Contract of all implementation required for Monad [PolEffect]
*
* Referring to [Category theory] this is a functor since implement [map]
* and a monad since implement [flatMap]
*/
interface PolEffect<T> {
boolean isDefined();
boolean isSuccess();
boolean isFailure();
PolMonad<T> pure(T input);
<A> PolMonad<A> map(Function<T, A> function);
<A> PolMonad<A> flatMap(Function<T, PolMonad<A>> function);
<A,B> PolMonad<Function<A,B>> curried(Function<T, Function<A, B>> function);
void forEach(Consumer<T> consumer);
PolMonad<T> fromOption(Option<T> input);
PolMonad<T> fromTry(Try<T> input);
}
/**
*
* Custom Monad implementation to control side-effects and allow to do operations:
*
* [map] transformation of the values that contains the [PolMonad]
* [flatMap] function to apply composition between [PolMonad] monads
* [curried] High order function. To receive and return a function
* [forEach] Consumer function, to iterate over all elements in the monad.
*/
static class PolMonad<T> implements PolEffect<T>{
public T value;
public Throwable sideEffect;
public PolMonad(){}
public PolMonad(T input){
this.value =input;
}
@Override
public boolean isDefined(){
return Option.of(this.value).isDefined();
}
@Override
public boolean isSuccess() {
return sideEffect==null;
}
@Override
public boolean isFailure() {
return sideEffect != null;
}
@Override
public PolMonad<T> pure(T a) {
return new PolMonad<>(a);
}
@Override
public <A> PolMonad<A> map(Function<T,A> function){
if (this.isDefined()) {
return new PolMonad<>(function.apply(this.value));
} else {
return new PolMonad<>();
}
}
@Override
public <A> PolMonad<A> flatMap(Function<T, PolMonad<A>> function){
if (this.isDefined()) {
return function.apply(this.value);
} else {
return new PolMonad<>();
}
}
@Override
public <A,B> PolMonad<Function<A,B>> curried(Function<T, Function<A, B>> function) {
return new PolMonad<>(function.apply(this.value));
}
@Override
public void forEach(Consumer<T> consumer){
consumer.accept(value);
}
@Override
public PolMonad<T> fromOption(Option<T> input) {
if (input.isDefined()) {
return new PolMonad<>(input.get());
} else {
this.value=null;
return this;
}
}
@Override
public PolMonad<T> fromTry(Try<T> input) {
if (input.isSuccess()) {
return new PolMonad<>(input.get());
} else {
this.sideEffect=input.getCause();
return this;
}
}
}
}