cats.SemigroupK.scala Maven / Gradle / Ivy
The newest version!
package cats
import scala.collection.immutable.{SortedMap, SortedSet}
import simulacrum.typeclass
import cats.data.Ior
/**
* SemigroupK is a universal semigroup which operates on kinds.
*
* This type class is useful when its type parameter F[_] has a
* structure that can be combined for any particular type. Thus,
* SemigroupK is like a Semigroup for kinds (i.e. parametrized
* types).
*
* A SemigroupK[F] can produce a Semigroup[F[A]] for any type A.
*
* Here's how to distinguish Semigroup and SemigroupK:
*
* - Semigroup[A] allows two A values to be combined.
*
* - SemigroupK[F] allows two F[A] values to be combined, for any A.
* The combination operation just depends on the structure of F,
* but not the structure of A.
*/
@typeclass trait SemigroupK[F[_]] { self =>
/**
* Combine two F[A] values.
*
* Example:
* {{{
* scala> import cats.implicits._
* scala> SemigroupK[List].combineK(List(1, 2), List(3, 4))
* res0: List[Int] = List(1, 2, 3, 4)
* }}}
*/
@simulacrum.op("<+>", alias = true)
def combineK[A](x: F[A], y: F[A]): F[A]
/**
* Given a type A, create a concrete Semigroup[F[A]].
*
* Example:
* {{{
* scala> import cats.implicits._
* scala> val s: Semigroup[List[Int]] = SemigroupK[List].algebra[Int]
* }}}
*/
def algebra[A]: Semigroup[F[A]] =
new Semigroup[F[A]] {
def combine(x: F[A], y: F[A]): F[A] = self.combineK(x, y)
}
/**
* "Compose" with a `G[_]` type to form a `SemigroupK` for `λ[α => F[G[α]]]`.
* Note that this universally works for any `G`, because the "inner" structure
* isn't considered when combining two instances.
*
* Example:
* {{{
* scala> import cats.implicits._
* scala> type ListOption[A] = List[Option[A]]
* scala> val s: SemigroupK[ListOption] = SemigroupK[List].compose[Option]
* scala> s.combineK(List(Some(1), None, Some(2)), List(Some(3), None))
* res0: List[Option[Int]] = List(Some(1), None, Some(2), Some(3), None)
* }}}
*/
def compose[G[_]]: SemigroupK[λ[α => F[G[α]]]] =
new ComposedSemigroupK[F, G] {
val F = self
}
/**
* Combines `F[A]` and `F[B]` into a `F[Either[A,B]]]`.
*
* Example:
* {{{
* scala> import cats.SemigroupK
* scala> import cats.data.NonEmptyList
* scala> SemigroupK[NonEmptyList].sum(NonEmptyList.one("abc"), NonEmptyList.one(2))
* res0: NonEmptyList[Either[String,Int]] = NonEmptyList(Left(abc), Right(2))
* }}}
*/
def sum[A, B](fa: F[A], fb: F[B])(implicit F: Functor[F]): F[Either[A, B]] =
combineK(F.map(fa)(Left(_)), F.map(fb)(Right(_)))
}
object SemigroupK extends ScalaVersionSpecificMonoidKInstances {
def align[F[_]: SemigroupK: Functor]: Align[F] = new Align[F] {
def align[A, B](fa: F[A], fb: F[B]): F[Ior[A, B]] =
SemigroupK[F].combineK(Functor[F].map(fa)(Ior.left), Functor[F].map(fb)(Ior.right))
def functor: Functor[F] = Functor[F]
}
implicit def catsMonoidKForOption: MonoidK[Option] = cats.instances.option.catsStdInstancesForOption
implicit def catsMonoidKForList: MonoidK[List] = cats.instances.list.catsStdInstancesForList
implicit def catsMonoidKForVector: MonoidK[Vector] = cats.instances.vector.catsStdInstancesForVector
implicit def catsMonoidKForSet: MonoidK[Set] = cats.instances.set.catsStdInstancesForSet
implicit def catsMonoidKForMap[K]: MonoidK[Map[K, *]] = cats.instances.map.catsStdMonoidKForMap[K]
implicit def catsSemigroupKForEither[A]: SemigroupK[Either[A, *]] =
cats.instances.either.catsStdSemigroupKForEither[A]
implicit def catsSemigroupKForSortedSet: SemigroupK[SortedSet] = cats.instances.sortedSet.catsStdInstancesForSortedSet
implicit def catsMonoidKForSortedMap[K: Order]: MonoidK[SortedMap[K, *]] =
cats.instances.sortedMap.catsStdMonoidKForSortedMap[K]
implicit def catsMonoidKForEndo: MonoidK[Endo] = cats.instances.function.catsStdMonoidKForFunction1
}