Skip to content

Commit 351e173

Browse files
committed
minor refactoring for Foldable
1 parent 155e3da commit 351e173

File tree

2 files changed

+99
-43
lines changed

2 files changed

+99
-43
lines changed

src/main/java/org/highj/typeclass1/foldable/Foldable.java

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
import org.highj.typeclass0.group.Monoid;
88
import org.highj.typeclass0.group.Semigroup;
99

10+
import java.util.function.BiFunction;
1011
import java.util.function.Function;
1112

1213
/**
1314
* The combined Foldable / Foldable1 type class.
14-
*
15+
* <p>
1516
* Minimal complete definition: 'foldr' OR 'foldMap'.
1617
*/
1718
public interface Foldable<F> {
@@ -20,47 +21,57 @@ default <A> A fold(Monoid<A> ma, __<F, A> nestedA) {
2021
return foldMap(ma, Function.<A>identity(), nestedA);
2122
}
2223

23-
default <A, B> B foldMap(final Monoid<B> mb, final Function<A, B> fn, __<F, A> nestedA) {
24-
return foldr((A a) -> b -> mb.apply(fn.apply(a), b), mb.identity(), nestedA);
24+
default <A, B> B foldMap(Monoid<B> mb, Function<A, B> fn, __<F, A> nestedA) {
25+
return foldr(a -> b -> mb.apply(fn.apply(a), b), mb.identity(), nestedA);
2526
}
2627

27-
default <A, B> B foldr(final Function<A, Function<B, B>> fn, B b, __<F, A> as) {
28-
//foldr f z t = appEndo (foldMap (Endo . f) t) z
29-
return foldMap(Functions.<B>endoMonoid(), fn, as).apply(b);
28+
default <A, B> B foldr(Function<A, Function<B, B>> fn, B b, __<F, A> as) {
29+
return foldMap(Functions.endoMonoid(), fn, as).apply(b);
30+
}
31+
32+
default <A, B> B foldr(BiFunction<A, B, B> fn, B b, __<F, A> as) {
33+
return foldr(x -> y -> fn.apply(x, y), b, as);
3034
}
3135

3236
//This is very inefficient, please override if possible.
33-
default <A, B> A foldl(final Function<A, Function<B, A>> fn, A a, __<F, B> bs) {
34-
//foldl f a bs = foldr (\b h -> \a ->h (f a b) ) id bs a
35-
return foldr((B b) -> (Function<A, A> h) -> (A x) -> h.apply(fn.apply(x).apply(b)), Function.<A>identity(), bs).apply(a);
37+
default <A, B> A foldl(Function<A, Function<B, A>> fn, A a, __<F, B> bs) {
38+
return foldr(b -> h -> x -> h.apply(fn.apply(x).apply(b)), Function.<A>identity(), bs).apply(a);
39+
}
40+
41+
default <A, B> A foldl(BiFunction<A, B, A> fn, A a, __<F, B> bs) {
42+
return foldr(b -> h -> x -> h.apply(fn.apply(x, b)), Function.<A>identity(), bs).apply(a);
3643
}
3744

3845
default <A> A fold1(Semigroup<A> sa, __<F, A> nestedA) {
39-
return foldMap1(sa, Function.<A>identity(), nestedA);
46+
return foldMap1(sa, Function.identity(), nestedA);
4047
}
4148

4249
default <A, B> B foldMap1(Semigroup<B> sa, Function<A, B> fn, __<F, A> nestedA) {
43-
Maybe<B> result = foldMap(Maybe.<B>monoid(sa), a -> Maybe.Just(fn.apply(a)), nestedA);
50+
Maybe<B> result = foldMap(Maybe.monoid(sa), a -> Maybe.Just(fn.apply(a)), nestedA);
4451
return result.getOrException("foldMap1 on mzero data structure");
4552
}
4653

47-
default <A> Maybe<A> foldr1(final Function<A, Function<A, A>> fn, __<F, A> nestedA) {
48-
return foldr((A one) -> (Maybe<A> maybeTwo) ->
49-
maybeTwo.isJust()
50-
? Maybe.Just(fn.apply(one).apply(maybeTwo.get()))
51-
: Maybe.Just(one),
52-
Maybe.<A>Nothing(), nestedA);
54+
default <A> Maybe<A> foldr1(Function<A, Function<A, A>> fn, __<F, A> nestedA) {
55+
return foldr(one -> maybeTwo -> maybeTwo.map(two -> fn.apply(one).apply(two)).orElse(Maybe.Just(one)),
56+
Maybe.Nothing(), nestedA);
57+
}
58+
59+
default <A> Maybe<A> foldr1(BiFunction<A, A, A> fn, __<F, A> nestedA) {
60+
return foldr((one, maybeTwo) -> maybeTwo.map(two -> fn.apply(one, two)).orElse(Maybe.Just(one)),
61+
Maybe.Nothing(), nestedA);
62+
}
63+
64+
default <A> Maybe<A> foldl1(Function<A, Function<A, A>> fn, __<F, A> nestedA) {
65+
return foldl(maybeOne -> two -> maybeOne.map(one -> fn.apply(one).apply(two)).orElse(Maybe.Just(two)),
66+
Maybe.Nothing(), nestedA);
5367
}
5468

55-
default <A> Maybe<A> foldl1(final Function<A, Function<A, A>> fn, __<F, A> nestedA) {
56-
return foldl((Maybe<A> maybeOne) -> (A two) ->
57-
maybeOne.isJust()
58-
? Maybe.Just(fn.apply(maybeOne.get()).apply(two))
59-
: Maybe.Just(two),
60-
Maybe.<A>Nothing(), nestedA);
69+
default <A> Maybe<A> foldl1(BiFunction<A, A, A> fn, __<F, A> nestedA) {
70+
return foldl((maybeOne, two) -> maybeOne.map(one -> fn.apply(one, two)).orElse(Maybe.Just(two)),
71+
Maybe.Nothing(), nestedA);
6172
}
6273

6374
default <A> List<A> toList(__<F, A> nestedA) {
64-
return foldr((A x) -> (List<A> xs) -> List.Cons(x, xs), List.<A>Nil(), nestedA);
75+
return foldr(x -> xs -> List.Cons(x, xs), List.Nil(), nestedA);
6576
}
6677
}

src/test/java/org/highj/typeclass1/foldable/FoldableTest.java

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,61 +3,106 @@
33
import org.highj.data.List;
44
import org.highj.data.Maybe;
55
import org.highj.data.num.Integers;
6+
import org.highj.function.Strings;
67
import org.junit.Test;
78

9+
import java.util.function.BiFunction;
810
import java.util.function.Function;
911

10-
import static org.junit.Assert.assertEquals;
11-
import static org.junit.Assert.assertTrue;
12+
import static org.assertj.core.api.Assertions.assertThat;
13+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1214

1315

1416
public class FoldableTest {
1517

1618
private final Function<String, Function<String, String>> wrapFn = a -> b -> "(" + a + "," + b + ")";
19+
private final BiFunction<String, String, String> wrapBiFn = (a, b) -> "(" + a + "," + b + ")";
1720

1821
@Test
19-
public void fold() {
22+
public void fold() {
2023
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
21-
int result = List.traversable.fold(Integers.multiplicativeMonoid, numbers);
22-
assertEquals(120, result);
24+
assertThat(List.traversable.fold(Integers.multiplicativeMonoid, numbers)).isEqualTo(120);
25+
26+
assertThat(List.traversable.fold(Integers.multiplicativeMonoid, List.of())).isEqualTo(1);
2327
}
2428

2529
@Test
26-
public void foldMap() {
30+
public void foldMap() {
2731
List<String> strings = List.of("a", "bb", "ccc", "dddd", "eeeee");
2832
int result = List.traversable.foldMap(Integers.multiplicativeMonoid, String::length, strings);
29-
assertEquals(120, result);
33+
assertThat(result).isEqualTo(120);
34+
35+
assertThat(List.traversable.foldMap(Integers.multiplicativeMonoid, String::length, List.of()))
36+
.isEqualTo(1);
3037
}
3138

3239
@Test
33-
public void foldr() {
40+
public void foldr() {
3441
List<String> strings = List.of("a", "e", "i", "o");
3542
String result = List.traversable.foldr(wrapFn, "u", strings);
36-
assertEquals("(a,(e,(i,(o,u))))", result);
43+
assertThat(result).isEqualTo("(a,(e,(i,(o,u))))");
44+
45+
result = List.traversable.foldr(wrapBiFn, "u", strings);
46+
assertThat(result).isEqualTo("(a,(e,(i,(o,u))))");
3747
}
3848

3949
@Test
40-
public void foldl() {
50+
public void foldl() {
4151
List<String> strings = List.of("e", "i", "o", "u");
4252
String result = List.traversable.foldl(wrapFn, "a", strings);
43-
assertEquals("((((a,e),i),o),u)", result);
53+
assertThat(result).isEqualTo("((((a,e),i),o),u)");
54+
55+
result = List.traversable.foldl(wrapBiFn, "a", strings);
56+
assertThat(result).isEqualTo("((((a,e),i),o),u)");
4457
}
4558

4659
@Test
47-
public void foldr1() {
60+
public void foldr1() {
4861
List<String> strings = List.of("a", "e", "i", "o", "u");
4962
Maybe<String> result = List.traversable.foldr1(wrapFn, strings);
50-
assertEquals("(a,(e,(i,(o,u))))", result.get());
51-
List<String> noStrings = List.of();
52-
assertTrue(List.traversable.foldr1(wrapFn, noStrings).isNothing());
63+
assertThat(result.get()).isEqualTo("(a,(e,(i,(o,u))))");
64+
assertThat(List.traversable.foldr1(wrapFn, List.of())).isEmpty();
65+
66+
result = List.traversable.foldr1(wrapBiFn, strings);
67+
assertThat(result.get()).isEqualTo("(a,(e,(i,(o,u))))");
68+
assertThat(List.traversable.foldr1(wrapBiFn, List.of())).isEmpty();
5369
}
5470

5571
@Test
56-
public void foldl1() {
72+
public void foldl1() {
5773
List<String> strings = List.of("a", "e", "i", "o", "u");
5874
Maybe<String> result = List.traversable.foldl1(wrapFn, strings);
59-
assertEquals("((((a,e),i),o),u)", result.get());
60-
List<String> noStrings = List.of();
61-
assertTrue(List.traversable.foldl1(wrapFn, noStrings).isNothing());
75+
assertThat(result.get()).isEqualTo("((((a,e),i),o),u)");
76+
assertThat(List.traversable.foldl1(wrapFn, List.of())).isEmpty();
77+
78+
result = List.traversable.foldl1(wrapBiFn, strings);
79+
assertThat(result.get()).isEqualTo("((((a,e),i),o),u)");
80+
assertThat(List.traversable.foldl1(wrapBiFn, List.of())).isEmpty();
81+
}
82+
83+
@Test
84+
public void fold1() {
85+
List<String> strings = List.of("a", "e", "i", "o", "u");
86+
assertThat(List.traversable.fold1(Strings.group, strings)).isEqualTo("aeiou");
87+
88+
assertThatThrownBy(() -> List.traversable.fold1(Strings.group, List.of()))
89+
.isInstanceOf(RuntimeException.class);
90+
}
91+
92+
@Test
93+
public void toList() {
94+
List<String> strings = List.of("a", "e", "i", "o", "u");
95+
List<String> result = List.traversable.toList(strings);
96+
assertThat(result).containsExactly("a", "e", "i", "o", "u");
97+
}
98+
99+
@Test
100+
public void foldMap1() {
101+
List<String> strings = List.of("a", "bb", "ccc", "dddd", "eeeee");
102+
Integer result = List.traversable.foldMap1(Integers.multiplicativeMonoid, String::length, strings);
103+
assertThat(result).isEqualTo(120);
104+
105+
assertThatThrownBy(() -> List.traversable.foldMap1(Integers.multiplicativeMonoid, String::length, List.of()))
106+
.isInstanceOf(RuntimeException.class);
62107
}
63108
}

0 commit comments

Comments
 (0)