fj.Semigroup 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 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 `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