Mercurial > hg > Members > tatsuki > functionaljava-master > core
diff src/main/java/fj/Monoid.java @ 0:fe80c1edf1be
add getLoop
author | tatsuki |
---|---|
date | Fri, 20 Mar 2015 21:04:03 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/fj/Monoid.java Fri Mar 20 21:04:03 2015 +0900 @@ -0,0 +1,387 @@ +package fj; + +import static fj.Function.curry; +import static fj.Function.compose; +import static fj.Function.flip; +import fj.data.Array; +import fj.data.List; +import fj.data.Natural; +import fj.data.Option; +import fj.data.Set; +import fj.data.Stream; +import static fj.data.Stream.iterableStream; + +import java.math.BigInteger; +import java.math.BigDecimal; + +/** + * A monoid abstraction to be defined across types of the given type argument. Implementations must + * follow the monoidal laws: + * <ul> + * <li><em>Left Identity</em>; forall x. sum(zero(), x) == x</li> + * <li><em>Right Identity</em>; forall x. sum(x, zero()) == x</li> + * <li><em>Associativity</em>; forall x. forall y. forall z. sum(sum(x, y), z) == sum(x, sum(y, z))</li> + * </ul> + * + * @version %build.number% + */ +public final class Monoid<A> { + private final F<A, F<A, A>> sum; + private final A zero; + + private Monoid(final F<A, F<A, A>> sum, final A zero) { + this.sum = sum; + this.zero = zero; + } + + /** + * Returns a semigroup projection of this monoid. + * + * @return A semigroup projection of this monoid. + */ + public Semigroup<A> semigroup() { + return Semigroup.semigroup(sum); + } + + /** + * Sums the two given arguments. + * + * @param a1 A value to sum with another. + * @param a2 A value to sum with another. + * @return The of the two given arguments. + */ + public A sum(final A a1, final A a2) { + return sum.f(a1).f(a2); + } + + /** + * Returns a function that sums the given value according to this monoid. + * + * @param a1 The value to sum. + * @return A function that sums the given value according to this monoid. + */ + public F<A, A> sum(final A a1) { + return sum.f(a1); + } + + /** + * Returns a function that sums according to this monoid. + * + * @return A function that sums according to this monoid. + */ + public F<A, F<A, A>> sum() { + return sum; + } + + /** + * The zero value for this monoid. + * + * @return The zero value for this monoid. + */ + public A zero() { + return zero; + } + + /** + * Sums the given values with right-fold. + * + * @param as The values to sum. + * @return The sum of the given values. + */ + public A sumRight(final List<A> as) { + return as.foldRight(sum, zero); + } + + /** + * Sums the given values with right-fold. + * + * @param as The values to sum. + * @return The sum of the given values. + */ + public A sumRight(final Stream<A> as) { + return as.foldRight(new F2<A, P1<A>, A>() { + public A f(final A a, final P1<A> ap1) { + return sum(a, ap1._1()); + } + }, zero); + } + + /** + * Sums the given values with left-fold. + * + * @param as The values to sum. + * @return The sum of the given values. + */ + public A sumLeft(final List<A> as) { + return as.foldLeft(sum, zero); + } + + /** + * Sums the given values with left-fold. + * + * @param as The values to sum. + * @return The sum of the given values. + */ + public A sumLeft(final Stream<A> as) { + return as.foldLeft(sum, zero); + } + + /** + * Returns a function that sums the given values with left-fold. + * + * @return a function that sums the given values with left-fold. + */ + public F<List<A>, A> sumLeft() { + return new F<List<A>, A>() { + public A f(final List<A> as) { + return sumLeft(as); + } + }; + } + + /** + * Returns a function that sums the given values with right-fold. + * + * @return a function that sums the given values with right-fold. + */ + public F<List<A>, A> sumRight() { + return new F<List<A>, A>() { + public A f(final List<A> as) { + return sumRight(as); + } + }; + } + + /** + * Returns a function that sums the given values with left-fold. + * + * @return a function that sums the given values with left-fold. + */ + public F<Stream<A>, A> sumLeftS() { + return new F<Stream<A>, A>() { + public A f(final Stream<A> as) { + return sumLeft(as); + } + }; + } + + /** + * Intersperses the given value between each two elements of the iterable, and sums the result. + * + * @param as An iterable of values to sum. + * @param a The value to intersperse between values of the given iterable. + * @return The sum of the given values and the interspersed value. + */ + public A join(final Iterable<A> as, final A a) { + final Stream<A> s = iterableStream(as); + return s.isEmpty() ? + zero : + s.foldLeft1(compose(sum, flip(sum).f(a))); + } + + /** + * Constructs a monoid from the given sum function and zero value, which must follow the monoidal + * laws. + * + * @param sum The sum function for the monoid. + * @param zero The zero for the monoid. + * @return A monoid instance that uses the given sun function and zero value. + */ + public static <A> Monoid<A> monoid(final F<A, F<A, A>> sum, final A zero) { + return new Monoid<A>(sum, zero); + } + + /** + * Constructs a monoid from the given sum function and zero value, which must follow the monoidal + * laws. + * + * @param sum The sum function for the monoid. + * @param zero The zero for the monoid. + * @return A monoid instance that uses the given sun function and zero value. + */ + public static <A> Monoid<A> monoid(final F2<A, A, A> sum, final A zero) { + return new Monoid<A>(curry(sum), zero); + } + + /** + * Constructs a monoid from the given semigroup and zero value, which must follow the monoidal laws. + * + * @param s The semigroup for the monoid. + * @param zero The zero for the monoid. + * @return A monoid instance that uses the given sun function and zero value. + */ + public static <A> Monoid<A> monoid(final Semigroup<A> s, final A zero) { + return new Monoid<A>(s.sum(), zero); + } + + /** + * A monoid that adds integers. + */ + public static final Monoid<Integer> intAdditionMonoid = monoid(Semigroup.intAdditionSemigroup, 0); + + /** + * A monoid that multiplies integers. + */ + public static final Monoid<Integer> intMultiplicationMonoid = monoid(Semigroup.intMultiplicationSemigroup, 1); + + /** + * A monoid that adds doubles. + */ + public static final Monoid<Double> doubleAdditionMonoid = monoid(Semigroup.doubleAdditionSemigroup, 0.0); + + /** + * A monoid that multiplies doubles. + */ + public static final Monoid<Double> doubleMultiplicationMonoid = monoid(Semigroup.doubleMultiplicationSemigroup, 1.0); + + /** + * A monoid that adds big integers. + */ + public static final Monoid<BigInteger> bigintAdditionMonoid = monoid(Semigroup.bigintAdditionSemigroup, BigInteger.ZERO); + + /** + * A monoid that multiplies big integers. + */ + public static final Monoid<BigInteger> bigintMultiplicationMonoid = + monoid(Semigroup.bigintMultiplicationSemigroup, BigInteger.ONE); + + /** + * A monoid that adds big decimals. + */ + public static final Monoid<BigDecimal> bigdecimalAdditionMonoid = + monoid(Semigroup.bigdecimalAdditionSemigroup, BigDecimal.ZERO); + + /** + * A monoid that multiplies big decimals. + */ + public static final Monoid<BigDecimal> bigdecimalMultiplicationMonoid = + monoid(Semigroup.bigdecimalMultiplicationSemigroup, BigDecimal.ONE); + + /** + * A monoid that adds natural numbers. + */ + public static final Monoid<Natural> naturalAdditionMonoid = + monoid(Semigroup.naturalAdditionSemigroup, Natural.ZERO); + + /** + * A monoid that multiplies natural numbers. + */ + public static final Monoid<Natural> naturalMultiplicationMonoid = + monoid(Semigroup.naturalMultiplicationSemigroup, Natural.ONE); + + /** + * A monoid that adds longs. + */ + public static final Monoid<Long> longAdditionMonoid = monoid(Semigroup.longAdditionSemigroup, 0L); + + /** + * A monoid that multiplies longs. + */ + public static final Monoid<Long> longMultiplicationMonoid = monoid(Semigroup.longMultiplicationSemigroup, 1L); + + /** + * A monoid that ORs booleans. + */ + public static final Monoid<Boolean> disjunctionMonoid = monoid(Semigroup.disjunctionSemigroup, false); + + /** + * A monoid that XORs booleans. + */ + public static final Monoid<Boolean> exclusiveDisjunctionMonoid = monoid(Semigroup.exclusiveDisjunctionSemiGroup, false); + + /** + * A monoid that ANDs booleans. + */ + public static final Monoid<Boolean> conjunctionMonoid = monoid(Semigroup.conjunctionSemigroup, true); + + /** + * A monoid that appends strings. + */ + public static final Monoid<String> stringMonoid = monoid(Semigroup.stringSemigroup, ""); + + /** + * A monoid that appends string buffers. + */ + public static final Monoid<StringBuffer> stringBufferMonoid = monoid(Semigroup.stringBufferSemigroup, new StringBuffer()); + + /** + * A monoid that appends string builders. + */ + public static final Monoid<StringBuilder> stringBuilderMonoid = monoid(Semigroup.stringBuilderSemigroup, new StringBuilder()); + + /** + * A monoid for functions. + * + * @param mb The monoid for the function codomain. + * @return A monoid for functions. + */ + public static <A, B> Monoid<F<A, B>> functionMonoid(final Monoid<B> mb) { + return monoid(Semigroup.<A, B>functionSemigroup(mb.semigroup()), Function.<A, B>constant(mb.zero)); + } + + /** + * A monoid for lists. + * + * @return A monoid for lists. + */ + public static <A> Monoid<List<A>> listMonoid() { + return monoid(Semigroup.<A>listSemigroup(), List.<A>nil()); + } + + /** + * A monoid for options. + * + * @return A monoid for options. + */ + public static <A> Monoid<Option<A>> optionMonoid() { + return monoid(Semigroup.<A>optionSemigroup(), Option.<A>none()); + } + + /** + * A monoid for options that take the first available value. + * + * @return A monoid for options that take the first available value. + */ + public static <A> Monoid<Option<A>> firstOptionMonoid() { + return monoid(Semigroup.<A>firstOptionSemigroup(), Option.<A>none()); + } + + /** + * A monoid for options that take the last available value. + * + * @return A monoid for options that take the last available value. + */ + public static <A> Monoid<Option<A>> lastOptionMonoid() { + return monoid(Semigroup.<A>lastOptionSemigroup(), Option.<A>none()); + } + + /** + * A monoid for streams. + * + * @return A monoid for streams. + */ + public static <A> Monoid<Stream<A>> streamMonoid() { + return monoid(Semigroup.<A>streamSemigroup(), Stream.<A>nil()); + } + + /** + * A monoid for arrays. + * + * @return A monoid for arrays. + */ + @SuppressWarnings({"unchecked"}) + public static <A> Monoid<Array<A>> arrayMonoid() { + return monoid(Semigroup.<A>arraySemigroup(), Array.<A>empty()); + } + + /** + * A monoid for sets. + * + * @param o An order for set elements. + * @return A monoid for sets whose elements have the given order. + */ + public static <A> Monoid<Set<A>> setMonoid(final Ord<A> o) { + return monoid(Semigroup.<A>setSemigroup(), Set.empty(o)); + } + +}