fj.Monoid Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of functionaljava Show documentation
Show all versions of functionaljava Show documentation
Functional Java is an open source library that supports closures for the Java programming language
package fj;
import static fj.Function.curry;
import static fj.Function.flip;
import fj.data.Array;
import fj.data.List;
import fj.data.IO;
import fj.data.IOFunctions;
import fj.data.Natural;
import fj.data.Option;
import fj.data.Set;
import fj.data.Stream;
import static fj.Function.flip;
import static fj.Semigroup.multiply1p;
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:
*
* - Left Identity; forall x. sum(zero(), x) == x
* - Right Identity; forall x. sum(x, zero()) == x
* - Associativity; forall x y z. sum(sum(x, y), z) == sum(x, sum(y, z))
*
*
* @version %build.number%
*/
public final class Monoid {
private final F> sum;
private final A zero;
private Monoid(final F> sum, final A zero) {
this.sum = sum;
this.zero = zero;
}
/**
* Composes this monoid with another.
*/
public Monoid>compose(Monoid m) {
return monoid((P2 x) -> (P2 y) ->
P.p(sum(x._1(), y._1()), m.sum(x._2(), y._2())), P.p(zero, m.zero));
}
/**
* Returns a semigroup projection of this monoid.
*
* @return A semigroup projection of this monoid.
*/
public Semigroup 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 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> sum() {
return sum;
}
/**
* The zero value for this monoid.
*
* @return The zero value for this monoid.
*/
public A zero() {
return zero;
}
/**
* Returns a value summed n
times (a + a + ... + a
).
* The default definition uses peasant multiplication, exploiting
* associativity to only require `O(log n)` uses of
* {@link #sum(Object, Object)}.
*
* @param n multiplier
* @param a the value to be reapeatly summed
* @return {@code a} summed {@code n} times. If {@code n <= 0}, returns
* {@code zero()}
*/
public A multiply(final int n, final A a) {
return (n <= 0)
? zero
: multiply1p(sum, n - 1, a);
}
/**
* 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 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 as) {
return as.foldRight((a, ap1) -> 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 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 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, A> sumLeft() {
return this::sumLeft;
}
/**
* Returns a function that sums the given values with right-fold.
*
* @return a function that sums the given values with right-fold.
*/
public F, A> sumRight() {
return this::sumRight;
}
/**
* Returns a function that sums the given values with left-fold.
*
* @return a function that sums the given values with left-fold.
*/
public F, A> sumLeftS() {
return this::sumLeft;
}
/**
* 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 as, final A a) {
final Stream s = iterableStream(as);
return s.isEmpty() ?
zero :
s.foldLeft1(Function.compose(sum, flip(sum).f(a)));
}
/**
* Swaps the arguments when summing.
*/
public Monoid dual() {
return monoid(flip(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 Monoid monoid(final F> sum, final A zero) {
return new Monoid<>(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 Monoid monoid(final F2 sum, final A zero) {
return new Monoid<>(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 Monoid monoid(final Semigroup s, final A zero) {
return new Monoid<>(s.sum(), zero);
}
/**
* A monoid that adds integers.
*/
public static final Monoid intAdditionMonoid = monoid(Semigroup.intAdditionSemigroup, 0);
/**
* A monoid that multiplies integers.
*/
public static final Monoid intMultiplicationMonoid = monoid(Semigroup.intMultiplicationSemigroup, 1);
/**
* A monoid that adds doubles.
*/
public static final Monoid doubleAdditionMonoid = monoid(Semigroup.doubleAdditionSemigroup, 0.0);
/**
* A monoid that multiplies doubles.
*/
public static final Monoid doubleMultiplicationMonoid = monoid(Semigroup.doubleMultiplicationSemigroup, 1.0);
/**
* A monoid that adds big integers.
*/
public static final Monoid bigintAdditionMonoid = monoid(Semigroup.bigintAdditionSemigroup, BigInteger.ZERO);
/**
* A monoid that multiplies big integers.
*/
public static final Monoid bigintMultiplicationMonoid =
monoid(Semigroup.bigintMultiplicationSemigroup, BigInteger.ONE);
/**
* A monoid that adds big decimals.
*/
public static final Monoid bigdecimalAdditionMonoid =
monoid(Semigroup.bigdecimalAdditionSemigroup, BigDecimal.ZERO);
/**
* A monoid that multiplies big decimals.
*/
public static final Monoid bigdecimalMultiplicationMonoid =
monoid(Semigroup.bigdecimalMultiplicationSemigroup, BigDecimal.ONE);
/**
* A monoid that adds natural numbers.
*/
public static final Monoid naturalAdditionMonoid =
monoid(Semigroup.naturalAdditionSemigroup, Natural.ZERO);
/**
* A monoid that multiplies natural numbers.
*/
public static final Monoid naturalMultiplicationMonoid =
monoid(Semigroup.naturalMultiplicationSemigroup, Natural.ONE);
/**
* A monoid that adds longs.
*/
public static final Monoid longAdditionMonoid = monoid(Semigroup.longAdditionSemigroup, 0L);
/**
* A monoid that multiplies longs.
*/
public static final Monoid longMultiplicationMonoid = monoid(Semigroup.longMultiplicationSemigroup, 1L);
/**
* A monoid that ORs booleans.
*/
public static final Monoid disjunctionMonoid = monoid(Semigroup.disjunctionSemigroup, false);
/**
* A monoid that XORs booleans.
*/
public static final Monoid exclusiveDisjunctionMonoid = monoid(Semigroup.exclusiveDisjunctionSemiGroup, false);
/**
* A monoid that ANDs booleans.
*/
public static final Monoid conjunctionMonoid = monoid(Semigroup.conjunctionSemigroup, true);
/**
* A monoid that appends strings.
*/
public static final Monoid stringMonoid = monoid(Semigroup.stringSemigroup, "");
/**
* A monoid that appends string buffers.
*/
public static final Monoid stringBufferMonoid = monoid(Semigroup.stringBufferSemigroup, new StringBuffer());
/**
* A monoid that appends string builders.
*/
public static final Monoid 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 Monoid> functionMonoid(final Monoid mb) {
return monoid(Semigroup.functionSemigroup(mb.semigroup()), Function.constant(mb.zero));
}
/**
* A monoid for lists.
*
* @return A monoid for lists.
*/
public static Monoid> listMonoid() {
return monoid(Semigroup.listSemigroup(), List.nil());
}
/**
* A monoid for options.
*
* @return A monoid for options.
*/
public static Monoid