Skip to content

Commit 3251c6e

Browse files
committed
#52 added ArrowLaw
1 parent 40853e4 commit 3251c6e

File tree

5 files changed

+183
-28
lines changed

5 files changed

+183
-28
lines changed

src/main/java/org/highj/typeclass2/arrow/Arrow.java

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,48 +7,46 @@
77

88
public interface Arrow<A> extends Category<A> {
99

10-
public <B, C> __2<A, B, C> arr(Function<B, C> fn);
10+
<B, C> __2<A, B, C> arr(Function<B, C> fn);
1111

12-
public <B, C, D> __2<A, T2<B, D>, T2<C, D>> first(__2<A, B, C> arrow);
12+
<B, C, D> __2<A, T2<B, D>, T2<C, D>> first(__2<A, B, C> arrow);
1313

14-
public default <B, C, D> __2<A, T2<D, B>, T2<D, C>> second(__2<A, B, C> arrow) {
14+
default <B, C, D> __2<A, T2<D, B>, T2<D, C>> second(__2<A, B, C> arrow) {
1515
__2<A, T2<D, B>, T2<B, D>> swapForth = arr(T2<D, B>::swap);
1616
__2<A, T2<B, D>, T2<C, D>> arrowFirst = first(arrow);
1717
__2<A, T2<C, D>, T2<D, C>> swapBack = arr(T2<C, D>::swap);
1818
return then(swapForth, arrowFirst, swapBack);
1919
}
2020

2121
//(***)
22-
public default <B, C, BB, CC> __2<A, T2<B, BB>, T2<C, CC>> split(__2<A, B, C> arr1, __2<A, BB, CC> arr2) {
22+
default <B, C, BB, CC> __2<A, T2<B, BB>, T2<C, CC>> split(__2<A, B, C> arr1, __2<A, BB, CC> arr2) {
2323
__2<A, T2<B, BB>, T2<C, BB>> one = first(arr1);
2424
__2<A, T2<C, BB>, T2<C, CC>> two = second(arr2);
2525
return then(one, two);
2626
}
2727

2828
//(&&&)
29-
public default <B, C, D> __2<A, B, T2<C, D>> fanout(__2<A, B, C> arr1, __2<A, B, D> arr2) {
29+
default <B, C, D> __2<A, B, T2<C, D>> fanout(__2<A, B, C> arr1, __2<A, B, D> arr2) {
3030
__2<A, B, T2<B, B>> duplicated = arr((B a) -> T2.<B, B>of(a, a));
3131
__2<A, T2<B, B>, T2<C, D>> splitted = split(arr1, arr2);
3232
return then(duplicated, splitted);
3333
}
3434

35-
public default <B> __2<A, B, B> returnA() {
35+
default <B> __2<A, B, B> returnA() {
3636
return arr(Function.<B>identity());
3737
}
3838

39-
//(^>>) :: Arrow a => (b -> c) -> a c d -> a b d
40-
public default <B, C, D> Function<__2<A, C, D>, __2<A, B, D>> precomposition(Function<B, C> fn) {
41-
//f ^>> a = arr f >>> a
39+
//(^>>)
40+
default <B, C, D> Function<__2<A, C, D>, __2<A, B, D>> precomposition(Function<B, C> fn) {
4241
return bc -> then(arr(fn), bc);
4342
}
4443

45-
//(^<<) :: Arrow a => (c -> d) -> a b c -> a b d
46-
public default <B, C, D> Function<__2<A, B, C>, __2<A, B, D>> postcomposition(final Function<C, D> fn) {
47-
//f ^<< a = arr f <<< a
44+
//(^<<)
45+
default <B, C, D> Function<__2<A, B, C>, __2<A, B, D>> postcomposition(final Function<C, D> fn) {
4846
return ab -> then(ab, arr(fn));
4947
}
5048

51-
public default <X> ApplicativeFromArrow<A,X> getApplicative() {
49+
default <X> ApplicativeFromArrow<A, X> getApplicative() {
5250
return () -> Arrow.this;
53-
}
51+
}
5452
}

src/main/java/org/highj/typeclass2/arrow/Category.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
import org.derive4j.hkt.__2;
44

5-
public interface Category<A> extends Semigroupoid<A>{
5+
public interface Category<A> extends Semigroupoid<A> {
66

77
// id (Control.Category)
8-
public <B> __2<A, B, B> identity();
8+
<B> __2<A, B, B> identity();
99

1010
}

src/main/java/org/highj/typeclass2/arrow/Semigroupoid.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ public interface Semigroupoid<A> {
88
<B, C, D> __2<A, B, D> dot(__2<A, C, D> cd, __2<A, B, C> bc);
99

1010
// (>>>) (Control.Category, Control.Arrow)
11-
public default <B, C, D> __2<A, B, D> then(__2<A, B, C> bc, __2<A, C, D> cd) {
11+
default <B, C, D> __2<A, B, D> then(__2<A, B, C> bc, __2<A, C, D> cd) {
1212
return dot(cd, bc);
1313
}
1414

1515
// 2x (>>>)
16-
public default <B, C, D, E> __2<A, B, E> then(__2<A, B, C> bc, __2<A, C, D> cd, __2<A, D, E> de){
16+
default <B, C, D, E> __2<A, B, E> then(__2<A, B, C> bc, __2<A, C, D> cd, __2<A, D, E> de) {
1717
return then(bc, then(cd, de));
1818
}
1919

2020
// 3x (>>>)
21-
public default <B, C, D, E, F> __2<A, B, F> then(__2<A, B, C> bc, __2<A, C, D> cd, __2<A, D, E> de, __2<A, E, F> ef) {
21+
default <B, C, D, E, F> __2<A, B, F> then(__2<A, B, C> bc, __2<A, C, D> cd, __2<A, D, E> de, __2<A, E, F> ef) {
2222
return then(bc, cd, then(de, ef));
2323
}
2424
}

src/test/java/org/highj/function/F1Test.java

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package org.highj.function;
22

3+
import org.derive4j.hkt.__2;
4+
import org.highj.Hkt;
35
import org.highj.data.Maybe;
6+
import org.highj.data.eq.Eq;
47
import org.highj.data.tuple.T2;
58
import org.highj.data.tuple.T3;
69
import org.highj.data.tuple.T4;
710
import org.highj.function.f1.F1Monad;
811
import org.highj.typeclass0.group.Monoid;
12+
import org.highj.typeclass2.arrow.ArrowLaw;
913
import org.junit.Test;
1014

1115
import java.sql.Timestamp;
@@ -100,16 +104,16 @@ public void monad() {
100104

101105
@Test
102106
public void fanout2() {
103-
F1<String, T2<Integer, String>> function = F1.fanout((F1<String, Integer>) String::length, F1.id());
107+
F1<String, T2<Integer, String>> function = F1.fanout((F1<String, Integer>) String::length, F1.id());
104108
T2<Integer, String> pair = function.apply("abcd");
105109
assertThat(pair._1()).isEqualTo(4);
106110
assertThat(pair._2()).isEqualTo("abcd");
107111
}
108112

109113
@Test
110114
public void fanout3() {
111-
F1<String, T3<Integer, String, Boolean>> function = F1.fanout(
112-
(F1<String, Integer>) String::length, F1.id(), (F1<String,Boolean>) s -> s.startsWith("ab"));
115+
F1<String, T3<Integer, String, Boolean>> function = F1.fanout(
116+
(F1<String, Integer>) String::length, F1.id(), (F1<String, Boolean>) s -> s.startsWith("ab"));
113117
T3<Integer, String, Boolean> triple = function.apply("abcd");
114118
assertThat(triple._1()).isEqualTo(4);
115119
assertThat(triple._2()).isEqualTo("abcd");
@@ -118,9 +122,9 @@ public void fanout3() {
118122

119123
@Test
120124
public void fanout4() {
121-
F1<String, T4<Integer, String, Boolean, String>> function = F1.fanout(
125+
F1<String, T4<Integer, String, Boolean, String>> function = F1.fanout(
122126
(F1<String, Integer>) String::length, F1.id(),
123-
(F1<String,Boolean>) s -> s.startsWith("ab"), (F1<String, String>) s -> s + s);
127+
(F1<String, Boolean>) s -> s.startsWith("ab"), (F1<String, String>) s -> s + s);
124128
T4<Integer, String, Boolean, String> quad = function.apply("abcd");
125129
assertThat(quad._1()).isEqualTo(4);
126130
assertThat(quad._2()).isEqualTo("abcd");
@@ -137,7 +141,10 @@ public void fromF1() {
137141
@Test
138142
public void lazy() {
139143
int[] sideEffect = {0};
140-
Supplier<Integer> supplier = F1.lazy(s -> { sideEffect[0] = 42; return s.length();}, "abcd");
144+
Supplier<Integer> supplier = F1.lazy(s -> {
145+
sideEffect[0] = 42;
146+
return s.length();
147+
}, "abcd");
141148
assertThat(sideEffect[0]).isEqualTo(0);
142149
assertThat(supplier.get()).isEqualTo(4);
143150
assertThat(sideEffect[0]).isEqualTo(42);
@@ -146,7 +153,10 @@ public void lazy() {
146153
@Test
147154
public void lazyFunction() {
148155
int[] sideEffect = {0};
149-
F1<String, Integer> f1 = s -> { sideEffect[0] = 42; return s.length();};
156+
F1<String, Integer> f1 = s -> {
157+
sideEffect[0] = 42;
158+
return s.length();
159+
};
150160
Supplier<Integer> supplier = f1.lazy("abcd");
151161
assertThat(sideEffect[0]).isEqualTo(0);
152162
assertThat(supplier.get()).isEqualTo(4);
@@ -156,7 +166,7 @@ public void lazyFunction() {
156166
@Test
157167
public void then() {
158168
F1<String, Integer> f = String::length;
159-
F1<Integer, Integer> g = x -> x*x;
169+
F1<Integer, Integer> g = x -> x * x;
160170
assertThat(f.then(g).apply("abcd")).isEqualTo(16);
161171
}
162172

@@ -190,7 +200,19 @@ public void arrow() {
190200
assertThat(dot.apply("foo")).isTrue();
191201
assertThat(dot.apply("foobar")).isFalse();
192202
}
193-
203+
204+
@Test
205+
public void arrowLaw() {
206+
new ArrowLaw<F1.µ>(F1.arrow) {
207+
@Override
208+
public <B, C> boolean areEqual(__2<F1.µ, B, C> one, __2<F1.µ, B, C> two, B b, Eq<C> eq) {
209+
F1<B, C> f1One = Hkt.asF1(one);
210+
F1<B, C> f1Two = Hkt.asF1(two);
211+
return eq.eq(f1One.apply(b), f1Two.apply(b));
212+
}
213+
}.test();
214+
}
215+
194216
@Test
195217
public void profunctor() {
196218
F1<String, Integer> f1 = String::length;
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package org.highj.typeclass2.arrow;
2+
3+
import org.derive4j.hkt.__2;
4+
import org.highj.Hkt;
5+
import org.highj.data.eq.Eq;
6+
import org.highj.data.tuple.T2;
7+
import org.highj.function.F1;
8+
import org.highj.util.Gen;
9+
import org.highj.util.Law;
10+
11+
import java.util.function.Function;
12+
13+
import static org.assertj.core.api.Assertions.assertThat;
14+
15+
public abstract class ArrowLaw<A> implements Law {
16+
17+
private final Arrow<A> arrow;
18+
19+
public ArrowLaw(Arrow<A> arrow) {
20+
this.arrow = arrow;
21+
}
22+
23+
public abstract <B, C> boolean areEqual(__2<A, B, C> one, __2<A, B, C> two, B b, Eq<C> eq);
24+
25+
26+
@Override
27+
public void test() {
28+
arrowIdentity();
29+
composition();
30+
arrFirst();
31+
firstComposition();
32+
t2_1();
33+
split();
34+
assoc();
35+
}
36+
37+
// arr id = id
38+
public void arrowIdentity() {
39+
__2<A, String, String> arrowOfId = arrow.arr(Function.identity());
40+
__2<A, String, String> arrowIdentity = arrow.identity();
41+
for (String s : Gen.stringGen.get(20)) {
42+
assertThat(areEqual(arrowOfId, arrowIdentity, s, Eq.fromEquals())).isTrue();
43+
}
44+
}
45+
46+
// arr (f >>> g) = arr f >>> arr g
47+
public void composition() {
48+
Function<String, Integer> f1 = String::length;
49+
Function<Integer, Integer> f2 = x -> x * x;
50+
__2<A, String, Integer> arrOfComposed = arrow.arr(f1.andThen(f2));
51+
__2<A, String, Integer> composedArr = arrow.then(arrow.arr(f1), arrow.arr(f2));
52+
for (String s : Gen.stringGen.get(20)) {
53+
assertThat(areEqual(arrOfComposed, composedArr, s, Eq.fromEquals())).isTrue();
54+
}
55+
}
56+
57+
// first (arr f) = arr (first f)
58+
public void arrFirst() {
59+
F1<String, Integer> fn = String::length;
60+
__2<A, T2<String, Boolean>, T2<Integer, Boolean>> firstArr = arrow.first(arrow.arr(fn));
61+
__2<A, T2<String, Boolean>, T2<Integer, Boolean>> arrFirst = arrow.arr(F1.arrow.first(fn));
62+
for (T2<String, Boolean> t2 : Gen.zip(Gen.stringGen, Gen.boolGen).get(20)) {
63+
assertThat(areEqual(firstArr, arrFirst, t2,
64+
T2.eq(Eq.fromEquals(), Eq.fromEquals()))).isTrue();
65+
}
66+
}
67+
68+
// first (f >>> g) = first f >>> first g
69+
public void firstComposition() {
70+
__2<A, String, Integer> f = arrow.arr(String::length);
71+
__2<A, Integer, Integer> g = arrow.arr(x -> x * x);
72+
__2<A, T2<String, Boolean>, T2<Integer, Boolean>> firstOfComposed =
73+
arrow.first(arrow.then(f, g));
74+
__2<A, T2<String, Boolean>, T2<Integer, Boolean>> composedFirst =
75+
arrow.then(arrow.first(f), arrow.first(g));
76+
for (T2<String, Boolean> t2 : Gen.zip(Gen.stringGen, Gen.boolGen).get(20)) {
77+
assertThat(areEqual(firstOfComposed, composedFirst, t2,
78+
T2.eq(Eq.fromEquals(), Eq.fromEquals()))).isTrue();
79+
}
80+
}
81+
82+
// first f >>> arr fst = arr fst >>> f
83+
public void t2_1() {
84+
__2<A, String, Integer> f = arrow.arr(String::length);
85+
86+
__2<A, T2<String, Boolean>, Integer> firstThenT2 = arrow.then(arrow.first(f), arrow.arr(T2::_1));
87+
__2<A, T2<String, Boolean>, Integer> T2ThenF = arrow.then(arrow.arr(T2::_1), f);
88+
89+
for (T2<String, Boolean> t2 : Gen.zip(Gen.stringGen, Gen.boolGen).get(20)) {
90+
assertThat(areEqual(firstThenT2, T2ThenF, t2, Eq.fromEquals())).isTrue();
91+
}
92+
}
93+
94+
// first f >>> arr (id *** g) = arr (id *** g) >>> first f
95+
public void split() {
96+
__2<A, String, Integer> f = arrow.arr(String::length);
97+
__2<F1.µ, Long, Long> g = (F1<Long, Long>) x -> x * x;
98+
99+
__2<A, T2<Integer, Long>, T2<Integer, Long>> g1 = arrow.arr(Hkt.asF1(F1.arrow.split(F1.arrow.identity(), g)));
100+
__2<A, T2<String, Long>, T2<Integer, Long>> firstSplitted = arrow.then(arrow.first(f), g1);
101+
102+
__2<A, T2<String, Long>, T2<String, Long>> g2 = arrow.arr(Hkt.asF1(F1.arrow.split(F1.arrow.identity(), g)));
103+
__2<A, T2<String, Long>, T2<Integer, Long>> splittedFirst = arrow.then(g2, arrow.first(f));
104+
105+
for (T2<String, Long> t2 : Gen.zip(Gen.stringGen, Gen.longGen).get(20)) {
106+
assertThat(areEqual(firstSplitted, splittedFirst, t2,
107+
T2.eq(Eq.fromEquals(), Eq.fromEquals()))).isTrue();
108+
}
109+
}
110+
111+
// first (first f) >>> arr assoc = arr assoc >>> first f -- where assoc ((a,b),c) = (a,(b,c))
112+
public void assoc() {
113+
__2<A, String, Integer> f = arrow.arr(String::length);
114+
115+
__2<A, T2<T2<String, Boolean>, Long>, T2<T2<Integer, Boolean>, Long>> firstFirst =
116+
arrow.first(arrow.first(f));
117+
__2<A, T2<T2<Integer, Boolean>, Long>, T2<Integer, T2<Boolean, Long>>> arrAssoc1 =
118+
arrow.arr(t2 -> T2.of(t2._1()._1(), T2.of(t2._1()._2(), t2._2())));
119+
__2<A, T2<T2<String, Boolean>, Long>, T2<Integer, T2<Boolean, Long>>> firstAssoc =
120+
arrow.then(firstFirst, arrAssoc1);
121+
122+
__2<A, T2<T2<String, Boolean>, Long>, T2<String, T2<Boolean, Long>>> arrAssoc2 =
123+
arrow.arr(t2 -> T2.of(t2._1()._1(), T2.of(t2._1()._2(), t2._2())));
124+
__2<A, T2<String, T2<Boolean, Long>>, T2<Integer, T2<Boolean, Long>>> first =
125+
arrow.first(f);
126+
__2<A, T2<T2<String, Boolean>, Long>, T2<Integer, T2<Boolean, Long>>> assocFirst =
127+
arrow.then(arrAssoc2, first);
128+
129+
for (T2<T2<String, Boolean>, Long> t2 : Gen.zip(Gen.zip(Gen.stringGen, Gen.boolGen),Gen.longGen).get(20)) {
130+
assertThat(areEqual(firstAssoc, assocFirst, t2,
131+
T2.eq(Eq.fromEquals(), T2.eq(Eq.fromEquals(), Eq.fromEquals())))).isTrue();
132+
}
133+
}
134+
135+
}

0 commit comments

Comments
 (0)