cats.kernel.Semigroup.scala Maven / Gradle / Ivy
The newest version!
package cats.kernel
import scala.annotation.tailrec
import scala.collection.immutable.{BitSet, Queue, SortedMap, SortedSet}
import scala.concurrent.duration.{Duration, FiniteDuration}
import scala.{specialized => sp}
import scala.util.{Failure, Success, Try}
import compat.scalaVersionSpecific._
/**
* A semigroup is any set `A` with an associative operation (`combine`).
*/
trait Semigroup[@sp(Int, Long, Float, Double) A] extends Any with Serializable {
/**
* Associative operation which combines two values.
*
* Example:
* {{{
* scala> import cats.kernel.instances.string._
* scala> import cats.kernel.instances.int._
* scala> import cats.kernel.instances.option._
*
* scala> Semigroup[String].combine("Hello ", "World!")
* res0: String = Hello World!
*
* scala> Semigroup[Option[Int]].combine(None, Some(1))
* res1: Option[Int] = Some(1)
* }}}
*/
def combine(x: A, y: A): A
/**
* Return `a` combined with itself `n` times.
*
* Example:
* {{{
* scala> import cats.kernel.instances.int._
* scala> import cats.kernel.instances.string._
*
* scala> Semigroup[Int].combineN(1, 10)
* res0: Int = 10
*
* scala> Semigroup[String].combineN("ha", 3)
* res1: String = hahaha
* }}}
*/
def combineN(a: A, n: Int): A =
if (n <= 0) throw new IllegalArgumentException("Repeated combining for semigroups must have n > 0")
else repeatedCombineN(a, n)
/**
* Return `a` combined with itself more than once.
*/
protected[this] def repeatedCombineN(a: A, n: Int): A = {
@tailrec def loop(b: A, k: Int, extra: A): A =
if (k == 1) combine(b, extra)
else {
val x = if ((k & 1) == 1) combine(b, extra) else extra
loop(combine(b, b), k >>> 1, x)
}
if (n == 1) a else loop(a, n - 1, a)
}
/**
* Given a sequence of `as`, combine them and return the total.
*
* If the sequence is empty, returns None. Otherwise, returns Some(total).
*
* Example:
* {{{
* scala> import cats.kernel.instances.string._
*
* scala> Semigroup[String].combineAllOption(List("One ", "Two ", "Three"))
* res0: Option[String] = Some(One Two Three)
*
* scala> Semigroup[String].combineAllOption(List.empty)
* res1: Option[String] = None
* }}}
*/
def combineAllOption(as: IterableOnce[A]): Option[A] =
as.reduceOption(combine)
}
abstract class SemigroupFunctions[S[T] <: Semigroup[T]] {
def combine[@sp(Int, Long, Float, Double) A](x: A, y: A)(implicit ev: S[A]): A =
ev.combine(x, y)
def maybeCombine[@sp(Int, Long, Float, Double) A](ox: Option[A], y: A)(implicit ev: S[A]): A =
ox match {
case Some(x) => ev.combine(x, y)
case None => y
}
def maybeCombine[@sp(Int, Long, Float, Double) A](x: A, oy: Option[A])(implicit ev: S[A]): A =
oy match {
case Some(y) => ev.combine(x, y)
case None => x
}
def isCommutative[A](implicit ev: S[A]): Boolean =
ev.isInstanceOf[CommutativeSemigroup[_]]
def isIdempotent[A](implicit ev: S[A]): Boolean =
ev.isInstanceOf[Band[_]]
def combineN[@sp(Int, Long, Float, Double) A](a: A, n: Int)(implicit ev: S[A]): A =
ev.combineN(a, n)
def combineAllOption[A](as: IterableOnce[A])(implicit ev: S[A]): Option[A] =
ev.combineAllOption(as)
}
object Semigroup
extends SemigroupFunctions[Semigroup]
with ScalaVersionSpecificMonoidInstances
with instances.TupleCommutativeGroupInstances
with GroupInstances {
/**
* Access an implicit `Semigroup[A]`.
*/
@inline final def apply[A](implicit ev: Semigroup[A]): Semigroup[A] = ev
/**
* Create a `Semigroup` instance from the given function.
*/
@inline def instance[A](cmb: (A, A) => A): Semigroup[A] = new Semigroup[A] {
override def combine(x: A, y: A): A = cmb(x, y)
}
implicit def catsKernelBoundedSemilatticeForBitSet: BoundedSemilattice[BitSet] =
cats.kernel.instances.bitSet.catsKernelStdSemilatticeForBitSet
implicit def catsKernelInstancesForUnit: BoundedSemilattice[Unit] with CommutativeGroup[Unit] =
cats.kernel.instances.unit.catsKernelStdAlgebraForUnit
implicit def catsKernelCommutativeGroupForByte: CommutativeGroup[Byte] =
cats.kernel.instances.byte.catsKernelStdGroupForByte
implicit def catsKernelCommutativeGroupForShort: CommutativeGroup[Short] =
cats.kernel.instances.short.catsKernelStdGroupForShort
implicit def catsKernelCommutativeGroupForInt: CommutativeGroup[Int] =
cats.kernel.instances.int.catsKernelStdGroupForInt
implicit def catsKernelCommutativeGroupForLong: CommutativeGroup[Long] =
cats.kernel.instances.long.catsKernelStdGroupForLong
implicit def catsKernelCommutativeGroupForBigInt: CommutativeGroup[BigInt] =
cats.kernel.instances.bigInt.catsKernelStdGroupForBigInt
implicit def catsKernelCommutativeGroupForBigDecimal: CommutativeGroup[BigDecimal] =
cats.kernel.instances.bigDecimal.catsKernelStdGroupForBigDecimal
implicit def catsKernelCommutativeGroupForDuration: CommutativeGroup[Duration] =
cats.kernel.instances.duration.catsKernelStdGroupForDuration
implicit def catsKernelCommutativeGroupForFiniteDuration: CommutativeGroup[FiniteDuration] =
cats.kernel.instances.all.catsKernelStdGroupForFiniteDuration
implicit def catsKernelCommutativeGroupForDouble: CommutativeGroup[Double] =
cats.kernel.instances.double.catsKernelStdGroupForDouble
implicit def catsKernelCommutativeGroupForFloat: CommutativeGroup[Float] =
cats.kernel.instances.float.catsKernelStdGroupForFloat
implicit def catsKernelMonoidForString: Monoid[String] = cats.kernel.instances.string.catsKernelStdMonoidForString
implicit def catsKernelMonoidForOption[A: Semigroup]: Monoid[Option[A]] =
cats.kernel.instances.option.catsKernelStdMonoidForOption[A]
implicit def catsKernelMonoidForList[A]: Monoid[List[A]] = cats.kernel.instances.list.catsKernelStdMonoidForList[A]
implicit def catsKernelMonoidForVector[A]: Monoid[Vector[A]] =
cats.kernel.instances.vector.catsKernelStdMonoidForVector[A]
implicit def catsKernelMonoidForQueue[A]: Monoid[Queue[A]] =
cats.kernel.instances.queue.catsKernelStdMonoidForQueue[A]
implicit def catsKernelCommutativeGroupForFunction0[A: CommutativeGroup]: CommutativeGroup[() => A] =
cats.kernel.instances.function.catsKernelCommutativeGroupForFunction0[A]
implicit def catsKernelCommutativeGroupForFunction1[A, B: CommutativeGroup]: CommutativeGroup[A => B] =
cats.kernel.instances.function.catsKernelCommutativeGroupForFunction1[A, B]
implicit def catsKernelBoundedSemilatticeForSet[A]: BoundedSemilattice[Set[A]] =
cats.kernel.instances.set.catsKernelStdSemilatticeForSet[A]
implicit def catsKernelBoundedSemilatticeForSortedSet[A: Order]: BoundedSemilattice[SortedSet[A]] =
cats.kernel.instances.sortedSet.catsKernelStdBoundedSemilatticeForSortedSet[A]
implicit def catsKernelCommutativeMonoidForMap[K, V: CommutativeSemigroup]: CommutativeMonoid[Map[K, V]] =
cats.kernel.instances.map.catsKernelStdCommutativeMonoidForMap[K, V]
implicit def catsKernelCommutativeMonoidForSortedMap[K: Order, V: CommutativeSemigroup]
: CommutativeMonoid[SortedMap[K, V]] =
cats.kernel.instances.sortedMap.catsKernelStdCommutativeMonoidForSortedMap[K, V]
}
private[kernel] trait GroupInstances extends BoundedSemilatticeInstances {
implicit def catsKernelGroupForFunction0[A: Group]: Group[() => A] =
cats.kernel.instances.function.catsKernelGroupForFunction0[A]
implicit def catsKernelGroupForFunction1[A, B: Group]: Group[A => B] =
cats.kernel.instances.function.catsKernelGroupForFunction1[A, B]
}
private[kernel] trait BoundedSemilatticeInstances extends SemilatticeInstances {
implicit def catsKernelBoundedSemilatticeForFunction0[A: BoundedSemilattice]: BoundedSemilattice[() => A] =
cats.kernel.instances.function.catsKernelBoundedSemilatticeForFunction0[A]
implicit def catsKernelBoundedSemilatticeForFunction1[A, B: BoundedSemilattice]: BoundedSemilattice[A => B] =
cats.kernel.instances.function.catsKernelBoundedSemilatticeForFunction1[A, B]
}
private[kernel] trait SemilatticeInstances extends CommutativeMonoidInstances {
implicit def catsKernelSemilatticeForFunction0[A: Semilattice]: Semilattice[() => A] =
cats.kernel.instances.function.catsKernelSemilatticeForFunction0[A]
implicit def catsKernelSemilatticeForFunction1[A, B: Semilattice]: Semilattice[A => B] =
cats.kernel.instances.function.catsKernelSemilatticeForFunction1[A, B]
}
private[kernel] trait CommutativeMonoidInstances extends MonoidInstances {
implicit def catsKernelCommutativeMonoidForFunction0[A: CommutativeMonoid]: CommutativeMonoid[() => A] =
cats.kernel.instances.function.catsKernelCommutativeMonoidForFunction0[A]
implicit def catsKernelCommutativeMonoidForFunction1[A, B: CommutativeMonoid]: CommutativeMonoid[A => B] =
cats.kernel.instances.function.catsKernelCommutativeMonoidForFunction1[A, B]
}
private[kernel] trait MonoidInstances extends BandInstances {
implicit def catsKernelMonoidForFunction0[A: Monoid]: Monoid[() => A] =
cats.kernel.instances.function.catsKernelMonoidForFunction0[A]
implicit def catsKernelMonoidForFunction1[A, B: Monoid]: Monoid[A => B] =
cats.kernel.instances.function.catsKernelMonoidForFunction1[A, B]
implicit def catsKernelMonoidForSortedMap[K: Order, V: Semigroup]: Monoid[SortedMap[K, V]] =
cats.kernel.instances.sortedMap.catsKernelStdMonoidForSortedMap[K, V]
implicit def catsKernelMonoidForEither[A, B: Monoid]: Monoid[Either[A, B]] =
cats.kernel.instances.either.catsDataMonoidForEither[A, B]
implicit def catsKernelMonoidForTry[A: Monoid]: Monoid[Try[A]] = new TryMonoid[A](Monoid[A])
}
private[kernel] trait BandInstances extends CommutativeSemigroupInstances {
implicit def catsKernelBandForFunction0[A: Band]: Band[() => A] =
cats.kernel.instances.function.catsKernelBandForFunction0[A]
implicit def catsKernelBandForFunction1[A, B: Band]: Band[A => B] =
cats.kernel.instances.function.catsKernelBandForFunction1[A, B]
}
private[kernel] trait CommutativeSemigroupInstances extends SemigroupInstances {
implicit def catsKernelCommutativeSemigroupForFunction0[A: CommutativeSemigroup]: CommutativeSemigroup[() => A] =
cats.kernel.instances.function.catsKernelCommutativeSemigroupForFunction0[A]
implicit def catsKernelCommutativeSemigroupForFunction1[A, B: CommutativeSemigroup]: CommutativeSemigroup[A => B] =
cats.kernel.instances.function.catsKernelCommutativeSemigroupForFunction1[A, B]
}
private[kernel] trait SemigroupInstances {
implicit def catsKernelSemigroupForFunction0[A: Semigroup]: Semigroup[() => A] =
cats.kernel.instances.function.catsKernelSemigroupForFunction0[A]
implicit def catsKernelSemigroupForFunction1[A, B: Semigroup]: Semigroup[A => B] =
cats.kernel.instances.function.catsKernelSemigroupForFunction1[A, B]
implicit def catsKernelSemigroupForEither[A, B: Semigroup]: Semigroup[Either[A, B]] =
cats.kernel.instances.either.catsDataSemigroupForEither[A, B]
implicit def catsKernelSemigroupForTry[A: Semigroup]: Semigroup[Try[A]] = new TrySemigroup[A](Semigroup[A])
}
private class TryMonoid[A](A: Monoid[A]) extends TrySemigroup[A](A) with Monoid[Try[A]] {
def empty: Try[A] = Success(A.empty)
}
private class TrySemigroup[A](A: Semigroup[A]) extends Semigroup[Try[A]] {
def combine(x: Try[A], y: Try[A]): Try[A] = (x, y) match {
case (Success(xv), Success(yv)) => Success(A.combine(xv, yv))
case (f @ Failure(_), _) => f
case (_, f) => f
}
}