All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javaslang.algebra.Monoid Maven / Gradle / Ivy

/*     / \____  _    _  ____   ______  / \ ____  __    _______
 *    /  /    \/ \  / \/    \ /  /\__\/  //    \/  \  //  /\__\   JΛVΛSLΛNG
 *  _/  /  /\  \  \/  /  /\  \\__\\  \  //  /\  \ /\\/ \ /__\ \   Copyright 2014-2017 Javaslang, http://javaslang.io
 * /___/\_/  \_/\____/\_/  \_/\__\/__/\__\_/  \_//  \__/\_____/   Licensed under the Apache License, Version 2.0
 */
package javaslang.algebra;

import javaslang.collection.Foldable;

import java.util.Objects;
import java.util.function.Function;

/**
 * 

A Monoid is a {@linkplain javaslang.algebra.Semigroup} (types with an associative binary operation) that has an * identity element {@code zero}.

*

Given a type {@code A}, instances of Monoid should satisfy the following laws:

*
    *
  • Associativity: {@code combine(combine(x,y),z) == combine(x,combine(y,z))} for any {@code x,y,z} of type * {@code A}.
  • *
  • Identity: {@code combine(zero(), x) == x == combine(x, zero())} for any {@code x} of type {@code A}.
  • *
*

Example: {@linkplain java.lang.String} is a Monoid with zero {@code ""} (empty String) and String concatenation * {@code +} as combine operation.

*

Please note that some types can be viewed as a monoid in more than one way, e.g. both addition and multiplication * on numbers.

* * Folding: * *
    *
  • {@link #fold(Monoid, Foldable)}
  • *
  • {@link #foldLeft(Monoid, Foldable)}
  • *
  • {@link #foldMap(Monoid, Foldable, Function)}
  • *
  • {@link #foldRight(Monoid, Foldable)}
  • *
* * @param A type. * @author Daniel Dietrich * @since 1.1.0 */ public interface Monoid extends Semigroup { /** * Factory method for monoids, taking a zero and a Semigroup. * * @param Value type * @param zero The zero of the Monoid. * @param semigroup The associative binary operation of the Monoid. Please note that * {@linkplain javaslang.algebra.Semigroup} is a {@linkplain java.lang.FunctionalInterface}. * @return a new Monoid on type A * @throws NullPointerException if {@code semigroup} is null */ static Monoid of(A zero, Semigroup semigroup) { Objects.requireNonNull(semigroup, "semigroup is null"); return new Monoid() { @Override public A combine(A a1, A a2) { return semigroup.combine(a1, a2); } @Override public A zero() { return zero; } }; } /** * The monoid of endomorphisms under composition. * * @param Value type * @return The monoid of endomorphisms of type A. */ static Monoid> endoMonoid() { return Monoid.of(Function.identity(), Function::compose); } /** * The unique neutral element regarding {@linkplain #combine(Object, Object)}. * * @return The zero element of this Monoid */ A zero(); // -- Fold operations /** * Folds the elements of {@code Foldable} from the left, starting with {@code monoid.zero()} * and successively calling {@code monoid::combine}. * * @param monoid A monoid, providing a {@code zero} and a {@code combine} function. * @param foldable A foldable * @param type of the foldable elements * @return a folded value * @throws NullPointerException if {@code monoid} or {@code foldable} is null */ static T fold(Monoid monoid, Foldable foldable) { Objects.requireNonNull(monoid, "monoid is null"); Objects.requireNonNull(foldable, "foldable is null"); return foldable.foldLeft(monoid.zero(), monoid::combine); } /** * Folds the elements of {@code Foldable} from the left, starting with {@code monoid.zero()} * and successively calling {@code monoid::combine}. * * @param monoid A monoid, providing a {@code zero} and a {@code combine} function. * @param foldable A foldable * @param type of the foldable elements * @return a folded value * @throws NullPointerException if {@code monoid} is null */ static T foldLeft(Monoid monoid, Foldable foldable) { Objects.requireNonNull(monoid, "monoid is null"); Objects.requireNonNull(foldable, "foldable is null"); return foldable.foldLeft(monoid.zero(), monoid::combine); } /** * Maps this elements to a {@code Monoid} and applies {@code foldLeft}, starting with {@code monoid.zero()}: *

     *  foldLeft(monoid.zero(), (ys, x) -> monoid.combine(ys, mapper.apply(x)));
     * 
* * @param monoid A Monoid * @param foldable A foldable * @param mapper A mapper * @param type of the foldable elements * @param Component type of the given monoid. * @return the folded monoid value. * @throws NullPointerException if {@code monoid} or {@code mapper} is null */ static U foldMap(Monoid monoid, Foldable foldable, Function mapper) { Objects.requireNonNull(monoid, "monoid is null"); Objects.requireNonNull(foldable, "foldable is null"); Objects.requireNonNull(mapper, "mapper is null"); return foldable.foldLeft(monoid.zero(), (ys, x) -> monoid.combine(ys, mapper.apply(x))); } /** * Folds this elements from the right, starting with {@code monoid.zero()} and successively calling {@code monoid::combine}. * * @param monoid A monoid, providing a {@code zero} and a {@code combine} function. * @param foldable A foldable * @param type of the foldable elements * @return a folded value * @throws NullPointerException if {@code monoid} is null */ static T foldRight(Monoid monoid, Foldable foldable) { Objects.requireNonNull(monoid, "monoid is null"); Objects.requireNonNull(foldable, "foldable is null"); return foldable.foldRight(monoid.zero(), monoid::combine); } }