Skip to content

Commit 435f3a5

Browse files
committed
Adding EndoK monoid
1 parent 79bd928 commit 435f3a5

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
66
## [Unreleased]
77
### Added
88
- `Writer`, the writer monad
9+
- `EndoK`, a monoid formed under endomorphism for any monad
910

1011
## [5.0.0] - 2019-09-23
1112
### Changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.jnape.palatable.lambda.monoid.builtin;
2+
3+
import com.jnape.palatable.lambda.functions.Fn1;
4+
import com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft;
5+
import com.jnape.palatable.lambda.functions.specialized.MonoidFactory;
6+
import com.jnape.palatable.lambda.functions.specialized.Pure;
7+
import com.jnape.palatable.lambda.monad.MonadRec;
8+
import com.jnape.palatable.lambda.monad.SafeT;
9+
import com.jnape.palatable.lambda.monoid.Monoid;
10+
11+
import static com.jnape.palatable.lambda.functions.specialized.Kleisli.kleisli;
12+
import static com.jnape.palatable.lambda.monad.SafeT.safeT;
13+
14+
/**
15+
* The monoid formed under monadic endomorphism.
16+
*
17+
* @param <M> the {@link MonadRec} witness
18+
* @param <A> the carrier type
19+
* @param <MA> the fully witnessed {@link MonadRec} type
20+
*/
21+
public final class EndoK<M extends MonadRec<?, M>, A, MA extends MonadRec<A, M>> implements
22+
MonoidFactory<Pure<M>, Fn1<A, MA>> {
23+
24+
private static final EndoK<?, ?, ?> INSTANCE = new EndoK<>();
25+
26+
@Override
27+
public Monoid<Fn1<A, MA>> checkedApply(Pure<M> pureM) {
28+
return new Monoid<Fn1<A, MA>>() {
29+
@Override
30+
public Fn1<A, MA> identity() {
31+
return pureM::apply;
32+
}
33+
34+
@Override
35+
public Fn1<A, MA> checkedApply(Fn1<A, MA> f, Fn1<A, MA> g) {
36+
return a -> kleisli(f).andThen(g::apply).apply(a);
37+
}
38+
39+
@Override
40+
public <B> Fn1<A, MA> foldMap(Fn1<? super B, ? extends Fn1<A, MA>> fn, Iterable<B> bs) {
41+
return a -> FoldLeft.foldLeft((f, b) -> f.fmap(ma -> ma.flatMap(a_ -> safeT(fn.apply(b).apply(a_)))),
42+
safeT(identity()).fmap(SafeT::safeT),
43+
bs)
44+
.<Fn1<A, SafeT<M, A>>>runSafeT()
45+
.apply(a)
46+
.runSafeT();
47+
}
48+
};
49+
}
50+
51+
@SuppressWarnings("unchecked")
52+
public static <M extends MonadRec<?, M>, A, MA extends MonadRec<A, M>> EndoK<M, A, MA> endoK() {
53+
return (EndoK<M, A, MA>) INSTANCE;
54+
}
55+
56+
public static <M extends MonadRec<?, M>, A, MA extends MonadRec<A, M>> Monoid<Fn1<A, MA>> endoK(Pure<M> pureM) {
57+
return EndoK.<M, A, MA>endoK().apply(pureM);
58+
}
59+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.jnape.palatable.lambda.monoid.builtin;
2+
3+
import com.jnape.palatable.lambda.functions.Fn1;
4+
import com.jnape.palatable.lambda.functor.builtin.Identity;
5+
import com.jnape.palatable.lambda.monoid.Monoid;
6+
import org.junit.Test;
7+
8+
import static com.jnape.palatable.lambda.functions.builtin.fn2.Replicate.replicate;
9+
import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity;
10+
import static com.jnape.palatable.lambda.monoid.builtin.EndoK.endoK;
11+
import static org.junit.Assert.assertEquals;
12+
import static testsupport.Constants.STACK_EXPLODING_NUMBER;
13+
14+
public class EndoKTest {
15+
16+
@Test
17+
public void identity() {
18+
Monoid<Fn1<Integer, Identity<Integer>>> endoK = endoK(pureIdentity());
19+
assertEquals(new Identity<>(1), endoK.identity().apply(1));
20+
}
21+
22+
@Test
23+
public void monoid() {
24+
Monoid<Fn1<Integer, Identity<Integer>>> endoK = endoK(pureIdentity());
25+
assertEquals(new Identity<>(3),
26+
endoK.apply(x -> new Identity<>(x + 1), x -> new Identity<>(x + 2)).apply(0));
27+
}
28+
29+
@Test
30+
public void stackSafe() {
31+
Monoid<Fn1<Integer, Identity<Integer>>> endoK = endoK(pureIdentity());
32+
assertEquals(new Identity<>(0), endoK.reduceLeft(replicate(STACK_EXPLODING_NUMBER, Identity::new)).apply(0));
33+
}
34+
}

0 commit comments

Comments
 (0)