001    package fj.pre;
002    
003    import fj.F;
004    import fj.F2;
005    import static fj.Function.curry;
006    import fj.P1;
007    import fj.P2;
008    import fj.Unit;
009    import fj.data.*;
010    
011    import java.math.BigInteger;
012    import java.math.BigDecimal;
013    
014    /**
015     * Implementations must satisfy the law of associativity:
016     * <ul>
017     * <li><em>Associativity</em>; forall x. forall y. forall z. sum(sum(x, y), z) == sum(x, sum(y, z))</li>
018     * </ul>
019     *
020     * @version %build.number%<br>
021     *          <ul>
022     *          <li>$LastChangedRevision: 159 $</li>
023     *          <li>$LastChangedDate: 2009-05-31 17:41:43 +1000 (Sun, 31 May 2009) $</li>
024     *          </ul>
025     */
026    public final class Semigroup<A> {
027      private final F<A, F<A, A>> sum;
028    
029      private Semigroup(final F<A, F<A, A>> sum) {
030        this.sum = sum;
031      }
032    
033      /**
034       * Sums the two given arguments.
035       *
036       * @param a1 A value to sum with another.
037       * @param a2 A value to sum with another.
038       * @return The of the two given arguments.
039       */
040      public A sum(final A a1, final A a2) {
041        return sum.f(a1).f(a2);
042      }
043    
044      /**
045       * Returns a function that sums the given value according to this semigroup.
046       *
047       * @param a1 The value to sum.
048       * @return A function that sums the given value according to this semigroup.
049       */
050      public F<A, A> sum(final A a1) {
051        return sum.f(a1);
052      }
053    
054      /**
055       * Returns a function that sums according to this semigroup.
056       *
057       * @return A function that sums according to this semigroup.
058       */
059      public F<A, F<A, A>> sum() {
060        return sum;
061      }
062    
063      /**
064       * Constructs a semigroup from the given function.
065       *
066       * @param sum The function to construct this semigroup with.
067       * @return A semigroup from the given function.
068       */
069      public static <A> Semigroup<A> semigroup(final F<A, F<A, A>> sum) {
070        return new Semigroup<A>(sum);
071      }
072    
073      /**
074       * Constructs a semigroup from the given function.
075       *
076       * @param sum The function to construct this semigroup with.
077       * @return A semigroup from the given function.
078       */
079      public static <A> Semigroup<A> semigroup(final F2<A, A, A> sum) {
080        return new Semigroup<A>(curry(sum));
081      }
082    
083      /**
084       * A semigroup that adds integers.
085       */
086      public static final Semigroup<Integer> intAdditionSemigroup = semigroup(new F2<Integer, Integer, Integer>() {
087        public Integer f(final Integer i1, final Integer i2) {
088          return i1 + i2;
089        }
090      });
091    
092      /**
093       * A semigroup that multiplies integers.
094       */
095      public static final Semigroup<Integer> intMultiplicationSemigroup = semigroup(new F2<Integer, Integer, Integer>() {
096        public Integer f(final Integer i1, final Integer i2) {
097          return i1 * i2;
098        }
099      });
100    
101      /**
102       * A semigroup that yields the maximum of integers.
103       */
104      public static final Semigroup<Integer> intMaximumSemigroup = semigroup(Ord.intOrd.max);
105    
106      /**
107       * A semigroup that yields the minimum of integers.
108       */
109      public static final Semigroup<Integer> intMinimumSemigroup = semigroup(Ord.intOrd.min);
110    
111      /**
112       * A semigroup that adds big integers.
113       */
114      public static final Semigroup<BigInteger> bigintAdditionSemigroup =
115          semigroup(new F2<BigInteger, BigInteger, BigInteger>() {
116            public BigInteger f(final BigInteger i1, final BigInteger i2) {
117              return i1.add(i2);
118            }
119          });
120    
121      /**
122       * A semigroup that multiplies big integers.
123       */
124      public static final Semigroup<BigInteger> bigintMultiplicationSemigroup =
125          semigroup(new F2<BigInteger, BigInteger, BigInteger>() {
126            public BigInteger f(final BigInteger i1, final BigInteger i2) {
127              return i1.multiply(i2);
128            }
129          });
130    
131      /**
132       * A semigroup that yields the maximum of big integers.
133       */
134      public static final Semigroup<BigInteger> bigintMaximumSemigroup = semigroup(Ord.bigintOrd.max);
135    
136      /**
137       * A semigroup that yields the minimum of big integers.
138       */
139      public static final Semigroup<BigInteger> bigintMinimumSemigroup = semigroup(Ord.bigintOrd.min);
140    
141      /**
142       * A semigroup that adds big decimals.
143       */
144      public static final Semigroup<BigDecimal> bigdecimalAdditionSemigroup =
145          semigroup(new F2<BigDecimal, BigDecimal, BigDecimal>() {
146            public BigDecimal f(final BigDecimal i1, final BigDecimal i2) {
147              return i1.add(i2);
148            }
149          });
150    
151      /**
152       * A semigroup that multiplies big decimals.
153       */
154      public static final Semigroup<BigDecimal> bigdecimalMultiplicationSemigroup =
155          semigroup(new F2<BigDecimal, BigDecimal, BigDecimal>() {
156            public BigDecimal f(final BigDecimal i1, final BigDecimal i2) {
157              return i1.multiply(i2);
158            }
159          });
160    
161      /**
162       * A semigroup that yields the maximum of big decimals.
163       */
164      public static final Semigroup<BigDecimal> bigDecimalMaximumSemigroup = semigroup(Ord.bigdecimalOrd.max);
165    
166      /**
167       * A semigroup that yields the minimum of big decimals.
168       */
169      public static final Semigroup<BigDecimal> bigDecimalMinimumSemigroup = semigroup(Ord.bigdecimalOrd.min);
170    
171      /**
172       * A semigroup that multiplies natural numbers.
173       */
174      public static final Semigroup<Natural> naturalMultiplicationSemigroup =
175          semigroup(new F2<Natural, Natural, Natural>() {
176            public Natural f(final Natural n1, final Natural n2) {
177              return n1.multiply(n2);
178            }
179          });
180    
181      /**
182       * A semigroup that multiplies natural numbers.
183       */
184      public static final Semigroup<Natural> naturalAdditionSemigroup =
185          semigroup(new F2<Natural, Natural, Natural>() {
186            public Natural f(final Natural n1, final Natural n2) {
187              return n1.add(n2);
188            }
189          });
190    
191      /**
192       * A semigroup that yields the maximum of natural numbers.
193       */
194      public static final Semigroup<Natural> naturalMaximumSemigroup = semigroup(Ord.naturalOrd.max);
195    
196      /**
197       * A semigroup that yields the minimum of natural numbers.
198       */
199      public static final Semigroup<Natural> naturalMinimumSemigroup = semigroup(Ord.naturalOrd.min);
200    
201      /**
202       * A semigroup that adds longs.
203       */
204      public static final Semigroup<Long> longAdditionSemigroup = semigroup(new F2<Long, Long, Long>() {
205        public Long f(final Long x, final Long y) {
206          return x + y;
207        }
208      });
209    
210      /**
211       * A semigroup that multiplies longs.
212       */
213      public static final Semigroup<Long> longMultiplicationSemigroup = semigroup(new F2<Long, Long, Long>() {
214        public Long f(final Long x, final Long y) {
215          return x * y;
216        }
217      });
218    
219      /**
220       * A semigroup that yields the maximum of longs.
221       */
222      public static final Semigroup<Long> longMaximumSemigroup = semigroup(Ord.longOrd.max);
223    
224      /**
225       * A semigroup that yields the minimum of longs.
226       */
227      public static final Semigroup<Long> longMinimumSemigroup = semigroup(Ord.longOrd.min);
228    
229      /**
230       * A semigroup that ORs booleans.
231       */
232      public static final Semigroup<Boolean> disjunctionSemigroup = semigroup(new F2<Boolean, Boolean, Boolean>() {
233        public Boolean f(final Boolean b1, final Boolean b2) {
234          return b1 || b2;
235        }
236      });
237    
238      /**
239       * A semigroup that XORs booleans.
240       */
241      public static final Semigroup<Boolean> exclusiveDisjunctionSemiGroup = semigroup(new F2<Boolean, Boolean, Boolean>() {
242        public Boolean f(final Boolean p, final Boolean q) {
243          return p && !q || !p && q;
244        }
245      });
246    
247      /**
248       * A semigroup that ANDs booleans.
249       */
250      public static final Semigroup<Boolean> conjunctionSemigroup = semigroup(new F2<Boolean, Boolean, Boolean>() {
251        public Boolean f(final Boolean b1, final Boolean b2) {
252          return b1 && b2;
253        }
254      });
255    
256      /**
257       * A semigroup that appends strings.
258       */
259      public static final Semigroup<String> stringSemigroup = semigroup(new F2<String, String, String>() {
260        public String f(final String s1, final String s2) {
261          return s1 + s2;
262        }
263      });
264    
265      /**
266       * A semigroup that appends string buffers.
267       */
268      public static final Semigroup<StringBuffer> stringBufferSemigroup =
269          semigroup(new F2<StringBuffer, StringBuffer, StringBuffer>() {
270            public StringBuffer f(final StringBuffer s1, final StringBuffer s2) {
271              return new StringBuffer(s1).append(s2);
272            }
273          });
274    
275      /**
276       * A semigroup that appends string builders.
277       */
278      public static final Semigroup<StringBuilder> stringBuilderSemigroup =
279          semigroup(new F2<StringBuilder, StringBuilder, StringBuilder>() {
280            public StringBuilder f(final StringBuilder s1, final StringBuilder s2) {
281              return new StringBuilder(s1).append(s2);
282            }
283          });
284    
285      /**
286       * A semigroup for functions.
287       *
288       * @param sb The smeigroup for the codomain.
289       * @return A semigroup for functions.
290       */
291      public static <A, B> Semigroup<F<A, B>> functionSemigroup(final Semigroup<B> sb) {
292        return semigroup(new F2<F<A, B>, F<A, B>, F<A, B>>() {
293          public F<A, B> f(final F<A, B> a1, final F<A, B> a2) {
294            return new F<A, B>() {
295              public B f(final A a) {
296                return sb.sum(a1.f(a), a2.f(a));
297              }
298            };
299          }
300        });
301      }
302    
303      /**
304       * A semigroup for lists.
305       *
306       * @return A semigroup for lists.
307       */
308      public static <A> Semigroup<List<A>> listSemigroup() {
309        return semigroup(new F2<List<A>, List<A>, List<A>>() {
310          public List<A> f(final List<A> a1, final List<A> a2) {
311            return a1.append(a2);
312          }
313        });
314      }
315    
316      /**
317       * A semigroup for non-empty lists.
318       *
319       * @return A semigroup for non-empty lists.
320       */
321      public static <A> Semigroup<NonEmptyList<A>> nonEmptyListSemigroup() {
322        return semigroup(new F2<NonEmptyList<A>, NonEmptyList<A>, NonEmptyList<A>>() {
323          public NonEmptyList<A> f(final NonEmptyList<A> a1, final NonEmptyList<A> a2) {
324            return a1.append(a2);
325          }
326        });
327      }
328    
329      /**
330       * A semigroup for optional values.
331       *
332       * @return A semigroup for optional values.
333       */
334      public static <A> Semigroup<Option<A>> optionSemigroup() {
335        return semigroup(new F2<Option<A>, Option<A>, Option<A>>() {
336          public Option<A> f(final Option<A> a1, final Option<A> a2) {
337            return a1.isSome() ? a1 : a2;
338          }
339        });
340      }
341    
342      /**
343       * A semigroup for streams.
344       *
345       * @return A semigroup for streams.
346       */
347      public static <A> Semigroup<Stream<A>> streamSemigroup() {
348        return semigroup(new F2<Stream<A>, Stream<A>, Stream<A>>() {
349          public Stream<A> f(final Stream<A> a1, final Stream<A> a2) {
350            return a1.append(a2);
351          }
352        });
353      }
354    
355      /**
356       * A semigroup for arrays.
357       *
358       * @return A semigroup for arrays.
359       */
360      public static <A> Semigroup<Array<A>> arraySemigroup() {
361        return semigroup(new F2<Array<A>, Array<A>, Array<A>>() {
362          public Array<A> f(final Array<A> a1, final Array<A> a2) {
363            return a1.append(a2);
364          }
365        });
366      }
367    
368      /**
369       * A semigroup for unary products.
370       *
371       * @param sa A semigroup for the product's type.
372       * @return A semigroup for unary products.
373       */
374      public static <A> Semigroup<P1<A>> p1Semigroup(final Semigroup<A> sa) {
375        return semigroup(new F2<P1<A>, P1<A>, P1<A>>() {
376          public P1<A> f(final P1<A> a1, final P1<A> a2) {
377            return new P1<A>() {
378              public A _1() {
379                return sa.sum(a1._1(), a2._1());
380              }
381            };
382          }
383        });
384      }
385    
386      /**
387       * A semigroup for binary products.
388       *
389       * @param sa A semigroup for the product's first type.
390       * @param sb A semigroup for the product's second type.
391       * @return A semigroup for binary products.
392       */
393      public static <A, B> Semigroup<P2<A, B>> p2Semigroup(final Semigroup<A> sa, final Semigroup<B> sb) {
394        return semigroup(new F2<P2<A, B>, P2<A, B>, P2<A, B>>() {
395          public P2<A, B> f(final P2<A, B> a1, final P2<A, B> a2) {
396            return new P2<A, B>() {
397              public A _1() {
398                return sa.sum(a1._1(), a2._1());
399              }
400    
401              public B _2() {
402                return sb.sum(a1._2(), a2._2());
403              }
404            };
405          }
406        });
407      }
408    
409      /**
410       * A semigroup for the Unit value.
411       */
412      public static final Semigroup<Unit> unitSemigroup = semigroup(new F2<Unit, Unit, Unit>() {
413        public Unit f(final Unit u1, final Unit u2) {
414          return Unit.unit();
415        }
416      });
417    
418      /**
419       * A semigroup for sets.
420       *
421       * @return a semigroup for sets.
422       */
423      public static <A> Semigroup<Set<A>> setSemigroup() {
424        return semigroup(new F2<Set<A>, Set<A>, Set<A>>() {
425          public Set<A> f(final Set<A> a, final Set<A> b) {
426            return a.union(b);
427          }
428        });
429      }
430    
431    }