diff --git a/core/src/main/scala/cats/SemigroupK.scala b/core/src/main/scala/cats/SemigroupK.scala index c52ad604ab..adfdb3504b 100644 --- a/core/src/main/scala/cats/SemigroupK.scala +++ b/core/src/main/scala/cats/SemigroupK.scala @@ -31,9 +31,9 @@ import simulacrum.{op, typeclass} /** * Compose two SemigroupK intsances. */ - def composedWith[G[_]: SemigroupK]: SemigroupK[λ[α => F[G[α]]]] = + def compose[G[_]: SemigroupK]: SemigroupK[λ[α => F[G[α]]]] = new SemigroupK[λ[α => F[G[α]]]] { - def combine[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = combine(x, y) + def combine[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = self.combine(x, y) } /** diff --git a/tests/src/test/scala/cats/tests/ComposeTests.scala b/tests/src/test/scala/cats/tests/ComposeTests.scala new file mode 100644 index 0000000000..5aca2b5628 --- /dev/null +++ b/tests/src/test/scala/cats/tests/ComposeTests.scala @@ -0,0 +1,58 @@ +package cats +package tests + +import cats.data.{ NonEmptyList, NonEmptyVector, OneAnd } +import cats.laws.discipline.{ ApplicativeTests, FoldableTests, MonoidalTests, SemigroupKTests, arbitrary, eq }, arbitrary._, eq._ +import org.scalacheck.Arbitrary + +class ComposeTests extends CatsSuite { + // we have a lot of generated lists of lists in these tests. We have to tell + // Scalacheck to calm down a bit so we don't hit memory and test duration + // issues. + implicit override val generatorDrivenConfig: PropertyCheckConfiguration = + PropertyCheckConfig(maxSize = 5, minSuccessful = 20) + + { + // Applicative composition + + implicit val applicativeListVector: Applicative[Lambda[A => List[Vector[A]]]] = Applicative[List] compose Applicative[Vector] + implicit val iso = MonoidalTests.Isomorphisms.invariant[Lambda[A => List[Vector[A]]]] + + checkAll("Applicative[Lambda[A => List[Vector[A]]]]", ApplicativeTests[Lambda[A => List[Vector[A]]]].applicative[Int, Int, Int]) + } + + { + // Foldable composition + + implicit val foldableListVector: Foldable[Lambda[A => List[Vector[A]]]] = Foldable[List] compose Foldable[Vector] + + checkAll("Foldable[Lambda[A => List[Vector[A]]]]", FoldableTests[Lambda[A => List[Vector[A]]]].foldable[Int, Int]) + } + + { + // Reducible composition + + val nelReducible = + new NonEmptyReducible[NonEmptyList, List] { + def split[A](fa: NonEmptyList[A]): (A, List[A]) = (fa.head, fa.tail) + } + + val nevReducible = + new NonEmptyReducible[NonEmptyVector, Vector] { + def split[A](fa: NonEmptyVector[A]): (A, Vector[A]) = (fa.head, fa.tail) + } + + implicit val reducibleListVector: Reducible[Lambda[A => NonEmptyList[NonEmptyVector[A]]]] = nelReducible compose nevReducible + + // No Reducible-specific laws, so check the Foldable laws are satisfied + checkAll("Reducible[Lambda[A => List[Vector[A]]]]", FoldableTests[Lambda[A => NonEmptyList[NonEmptyVector[A]]]].foldable[Int, Int]) + } + + { + // SemigroupK composition + + implicit val semigroupKListVector: SemigroupK[Lambda[A => List[Vector[A]]]] = SemigroupK[List] compose SemigroupK[Vector] + + checkAll("SemigroupK[Lambda[A => List[Vector[A]]]]", SemigroupKTests[Lambda[A => List[Vector[A]]]].semigroupK[Int]) + } +}