
fj.Semigroup Maven / Gradle / Ivy
package fj;
import fj.data.Array;
import fj.data.DList;
import fj.data.List;
import fj.data.IO;
import fj.data.Natural;
import fj.data.NonEmptyList;
import fj.data.Option;
import fj.data.Set;
import fj.data.Stream;
import java.math.BigDecimal;
import java.math.BigInteger;
import static fj.F1Functions.dimap;
import static fj.Function.constant;
import static fj.Function.identity;
import static fj.Monoid.*;
import static fj.data.DList.listDList;
import static fj.data.Option.none;
import static fj.data.Option.some;
/**
* Implementations must satisfy the law of associativity:
*
* - Associativity; forall x. forall y. forall z. sum(sum(x, y), z) == sum(x, sum(y, z))
*
*
* @version %build.number%
*/
public final class Semigroup {
/**
* Primitives functions of Semigroup: minimal definition and overridable methods.
*/
public interface Definition {
A append(A a1, A a2);
default F prepend(A a) {
return a2 -> append(a, a2);
}
default A sum(A a, F0> as) {
return as.f().foldLeft(this::append, a);
}
default A multiply1p(int n, A a) {
if (n <= 0) {
return a;
}
A xTmp = a;
int yTmp = n;
A zTmp = a;
while (true) {
if ((yTmp & 1) == 1) {
zTmp = append(xTmp, zTmp);
if (yTmp == 1) {
return zTmp;
}
}
xTmp = append(xTmp, xTmp);
yTmp = (yTmp) >>> 1;
}
}
default Definition dual() {
return new Definition(){
@Override
public A append(A a1, A a2) {
return Definition.this.append(a2, a1);
}
@Override
public A multiply1p(int n, A a) {
return Definition.this.multiply1p(n, a);
}
};
}
}
/**
* Primitives functions of Semigroup: alternative minimal definition and overridable methods.
*/
public interface AltDefinition extends Definition {
@Override
F prepend(A a);
@Override
default A append(A a1, A a2) {
return prepend(a1).f(a2);
}
}
private final Definition def;
private Semigroup(final Definition def) {
this.def = def;
}
/**
* 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 def.append(a1, a2);
}
/**
* Returns a function that sums the given value according to this semigroup.
*
* @param a1 The value to sum.
* @return A function that sums the given value according to this semigroup.
*/
public F sum(final A a1) {
return def.prepend(a1);
}
/**
* Returns a function that sums according to this semigroup.
*
* @return A function that sums according to this semigroup.
*/
public F> sum() {
return def::prepend;
}
/**
* Returns a value summed n + 1
times (
* a + a + ... + a
) The default definition uses peasant
* multiplication, exploiting associativity to only require {@code O(log n)} uses of
* {@link #sum(Object, Object)}.
*
* @param n multiplier
* @param a the value to be reapeatly summed n + 1 times
* @return {@code a} summed {@code n} times. If {@code n <= 0}, returns
* {@code zero()}
*/
public A multiply1p(int n, A a) {
return def.multiply1p(n, a);
}
/**
* Sums the given values with left-fold.
*/
public A sumNel(final NonEmptyList as) {
return as.foldLeft1(def::append);
}
/**
* Sums the given values with left-fold, shortcutting the computation as early as possible.
*/
public A sumStream(A a, F0> as) {
return def.sum(a, as);
}
/**
* Swaps the arguments when summing.
*/
public Semigroup dual() {
return semigroupDef(def.dual());
}
/**
* Lifts the semigroup to obtain a trivial monoid.
*/
public Monoid
© 2015 - 2025 Weber Informatics LLC | Privacy Policy