View Javadoc

1   /*
2      Copyright 2015 Atlassian
3   
4      Licensed under the Apache License, Version 2.0 (the "License");
5      you may not use this file except in compliance with the License.
6      You may obtain a copy of the License at
7   
8          http://www.apache.org/licenses/LICENSE-2.0
9   
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15   */
16  
17  package io.atlassian.fugue;
18  
19  import static io.atlassian.fugue.Iterables.concat;
20  import static io.atlassian.fugue.Pair.pair;
21  import static java.util.Collections.singletonList;
22  
23  /**
24   * A Monoid is an algebraic structure consisting of an associative binary
25   * operation across the values of a given type (a monoid is a {@link Semigroup})
26   * and an identity element for this operation. Implementations must follow the
27   * monoidal laws:
28   * <ul>
29   * <li><em>Left Identity</em>; forall x. append(zero(), x) == x</li>
30   * <li><em>Right Identity</em>; forall x. append(x, zero()) == x</li>
31   * <li><em>Associativity</em>; forall x y z. append(append(x, y), z) ==
32   * append(x, append(y, z))</li>
33   * </ul>
34   * Methods {@link #sum(Iterable)} and {@link #multiply(int, Object)} can be
35   * overriden for performance reason, especially if {@link #sum(Iterable)} can be
36   * implemented to not require evaluation of the whole iterable. All other
37   * default methods should not be overriden.
38   *
39   * @see Semigroup
40   * @since 3.1
41   */
42  public interface Monoid<A> extends Semigroup<A> {
43  
44    /**
45     * The identity element value for this monoid.
46     *
47     * @return The identity element for this monoid.
48     */
49    A zero();
50  
51    /**
52     * Sums the given values.
53     *
54     * @param as The values to sum.
55     * @return The sum of the given values.
56     */
57    default A sum(final Iterable<A> as) {
58      return Semigroup.super.sumNonEmpty(zero(), as);
59    }
60  
61    /**
62     * Returns a value summed <code>n</code> times (<code>a + a + ... + a</code>).
63     * The default definition uses peasant multiplication, exploiting
64     * associativity to only require `O(log n)` uses of
65     * {@link #append(Object, Object)}.
66     *
67     * @param n multiplier
68     * @param a the value to be reapeatly summed
69     * @return {@code a} summed {@code n} times. If {@code n <= 0}, returns
70     * {@code zero()}
71     */
72    default A multiply(final int n, final A a) {
73      return (n <= 0) ? zero() : Semigroup.super.multiply1p(n - 1, a);
74    }
75  
76    // Derived methods: should not be overriden:
77  
78    /**
79     * Intersperses the given value between each two elements of the collection,
80     * and sums the result.
81     *
82     * @param as An iterable of values.
83     * @param a The value to intersperse between values of the given iterable.
84     * @return The sum of the given values and the interspersed value.
85     */
86    default A intersperse(final Iterable<? extends A> as, final A a) {
87      return sum(Iterables.intersperse(as, a));
88    }
89  
90    @Override default A sumNonEmpty(A head, Iterable<A> tail) {
91      return sum(concat(singletonList(head), tail));
92    }
93  
94    @Override default A multiply1p(int n, A a) {
95      return n == Integer.MAX_VALUE ? append(a, multiply(n, a)) : multiply(n + 1, a);
96    }
97  
98    /**
99     * Composes a monoid with another.
100    */
101   public static <A, B> Monoid<Pair<A, B>> compose(Monoid<A> ma, Monoid<B> mb) {
102     Pair<A, B> zero = pair(ma.zero(), mb.zero());
103     return new Monoid<Pair<A, B>>() {
104       @Override public Pair<A, B> append(Pair<A, B> p1, Pair<A, B> p2) {
105         return pair(ma.append(p1.left(), p2.left()), mb.append(p1.right(), p2.right()));
106       }
107 
108       @Override public Pair<A, B> zero() {
109         return zero;
110       }
111     };
112   }
113 
114   /**
115    * Return the dual Monoid.
116    *
117    * @param monoid a monoid.
118    * @return a Monoid appending in reverse order,
119    */
120   public static <A> Monoid<A> dual(Monoid<A> monoid) {
121     return new Monoid<A>() {
122       @Override public A append(A a1, A a2) {
123         return monoid.append(a2, a1);
124       }
125 
126       @Override public A zero() {
127         return monoid.zero();
128       }
129 
130       @Override public A multiply(int n, A a) {
131         return monoid.multiply(n, a);
132       }
133     };
134   }
135 }