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.law;
18  
19  import io.atlassian.fugue.Functions;
20  import io.atlassian.fugue.Iterables;
21  import io.atlassian.fugue.Semigroup;
22  
23  import java.util.function.BiFunction;
24  
25  /**
26   * Laws for a semigroup
27   */
28  public final class SemigroupLaws<A> {
29  
30    private final Semigroup<A> semigroup;
31  
32    /**
33     * Build a law instance to check semigroup properties
34     *
35     * @param semigroup a {@link io.atlassian.fugue.Semigroup} to check matches
36     * the desired behaviors of
37     */
38    public SemigroupLaws(final Semigroup<A> semigroup) {
39      this.semigroup = semigroup;
40    }
41  
42    /**
43     * A semigroup must not care about the order elements are combined. If you
44     * combine x with y and then with z the result should be the same as combining
45     * y with z and then with x.
46     *
47     * @param x an A object
48     * @param y an A object
49     * @param z an A object
50     * @return a {@link io.atlassian.fugue.law.IsEq} instance where
51     * append(append(x,y),z) is equal to append(x, append(y,z))
52     */
53    public IsEq<A> semigroupAssociative(final A x, final A y, final A z) {
54      return IsEq.isEq(semigroup.append(semigroup.append(x, y), z), semigroup.append(x, semigroup.append(y, z)));
55    }
56  
57    /**
58     * The {@link Semigroup#sumNonEmpty(Object, Iterable)} function of your
59     * semigroup must be equal to a
60     * {@link Functions#fold(BiFunction, Object, Iterable)} where append is used
61     * as the combining function, head is used as the initial value and tail is
62     * the iterable to check
63     *
64     * @param head an A
65     * @param tail a {@link java.lang.Iterable} of A's
66     * @return a {@link io.atlassian.fugue.law.IsEq} where sumeNonEmpty(head,
67     * tail) is equal to fold(append, head, tail)
68     */
69    public IsEq<A> sumNonEmptyEqualFold(final A head, final Iterable<A> tail) {
70      return IsEq.isEq(semigroup.sumNonEmpty(head, tail), Functions.fold(semigroup::append, head, tail));
71    }
72  
73    /**
74     * The {@link Semigroup#multiply1p(int, Object)} function of your semigroup
75     * must be equal to {@link Semigroup#sumNonEmpty(Object, Iterable)} applied to
76     * the input and an iterable containing {@code n - 1} copies of that input
77     *
78     * @param n a int representing the number of copies of the input to combine
79     * @param a an A
80     * @return a {@link io.atlassian.fugue.law.IsEq} where multiply(n,a) is equal
81     * to sumNonEmpty(a, take(n-1, cycle(a))
82     */
83    public IsEq<A> multiply1pEqualRepeatedAppend(final int n, final A a) {
84      return IsEq.isEq(semigroup.multiply1p(n, a), semigroup.sumNonEmpty(a, Iterables.take(n, Iterables.cycle(a))));
85    }
86  
87  }