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 }