Skip to content

Commit

Permalink
More tests + Nested
Browse files Browse the repository at this point in the history
  • Loading branch information
Luka Jacobowitz committed Dec 12, 2017
1 parent d8b496d commit bd825fe
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 21 deletions.
13 changes: 13 additions & 0 deletions core/src/main/scala/cats/InvariantSemigroupal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ import simulacrum.typeclass
object InvariantSemigroupal extends SemigroupalArityFunctions {
def semigroup[F[_], A](implicit f: InvariantSemigroupal[F], sg: Semigroup[A]): Semigroup[F[A]] =
new InvariantSemigroupalSemigroup[F, A](f, sg)

implicit def catsSemigroupalForMonoid: InvariantSemigroupal[Monoid] = new InvariantSemigroupal[Monoid] {
def product[A, B](fa: Monoid[A], fb: Monoid[B]): Monoid[(A, B)] = new Monoid[(A, B)] {
val empty = fa.empty -> fb.empty
def combine(x: (A, B), y: (A, B)): (A, B) = fa.combine(x._1, y._1) -> fb.combine(x._2, y._2)
}

def imap[A, B](fa: Monoid[A])(f: A => B)(g: B => A): Monoid[B] = new Monoid[B] {
def empty: B = f(fa.empty)

def combine(x: B, y: B): B = f(fa.combine(g(x), g(y)))
}
}
}

private[cats] class InvariantSemigroupalSemigroup[F[_], A](f: InvariantSemigroupal[F], sg: Semigroup[A]) extends Semigroup[F[A]] {
Expand Down
9 changes: 1 addition & 8 deletions core/src/main/scala/cats/Semigroupal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,4 @@ import simulacrum.typeclass
def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]
}

object Semigroupal extends SemigroupalArityFunctions {
implicit def catsSemigroupalForMonoid: Semigroupal[Monoid] = new Semigroupal[Monoid] {
def product[A, B](fa: Monoid[A], fb: Monoid[B]): Monoid[(A, B)] = new Monoid[(A, B)] {
val empty = fa.empty -> fb.empty
def combine(x: (A, B), y: (A, B)): (A, B) = fa.combine(x._1, y._1) -> fb.combine(x._2, y._2)
}
}
}
object Semigroupal extends SemigroupalArityFunctions
23 changes: 20 additions & 3 deletions core/src/main/scala/cats/data/Nested.scala
Original file line number Diff line number Diff line change
Expand Up @@ -142,27 +142,34 @@ private[data] sealed abstract class NestedInstances8 extends NestedInstances9 {
}

private[data] sealed abstract class NestedInstances9 extends NestedInstances10 {
implicit def catsDataInvariantSemigroupalApplyForNested[F[_]: InvariantSemigroupal, G[_]: Apply]: InvariantSemigroupal[Nested[F, G, ?]] =
new NestedInvariantSemigroupalApply[F, G] {
val FG: InvariantSemigroupal[λ[α => F[G[α]]]] = InvariantSemigroupal[F].composeApply[G]
}
}

private[data] sealed abstract class NestedInstances10 extends NestedInstances11 {
implicit def catsDataFunctorForNested[F[_]: Functor, G[_]: Functor]: Functor[Nested[F, G, ?]] =
new NestedFunctor[F, G] {
val FG: Functor[λ[α => F[G[α]]]] = Functor[F].compose[G]
}
}

private[data] sealed abstract class NestedInstances10 extends NestedInstances11 {
private[data] sealed abstract class NestedInstances11 extends NestedInstances12 {
implicit def catsDataInvariantForNested[F[_]: Invariant, G[_]: Invariant]: Invariant[Nested[F, G, ?]] =
new NestedInvariant[F, G] {
val FG: Invariant[λ[α => F[G[α]]]] = Invariant[F].compose[G]
}
}

private[data] sealed abstract class NestedInstances11 extends NestedInstances12 {
private[data] sealed abstract class NestedInstances12 extends NestedInstances13 {
implicit def catsDataInvariantForCovariantNested[F[_]: Invariant, G[_]: Functor]: Invariant[Nested[F, G, ?]] =
new NestedInvariant[F, G] {
val FG: Invariant[λ[α => F[G[α]]]] = Invariant[F].composeFunctor[G]
}
}

private[data] sealed abstract class NestedInstances12 {
private[data] sealed abstract class NestedInstances13 {
implicit def catsDataInvariantForNestedContravariant[F[_]: Invariant, G[_]: Contravariant]: Invariant[Nested[F, G, ?]] =
new NestedInvariant[F, G] {
val FG: Invariant[λ[α => F[G[α]]]] = Invariant[F].composeContravariant[G]
Expand Down Expand Up @@ -280,3 +287,13 @@ private[data] trait NestedContravariantMonoidal[F[_], G[_]] extends Contravarian
def product[A, B](fa: Nested[F, G, A], fb: Nested[F, G, B]): Nested[F, G, (A, B)] =
Nested(FG.product(fa.value, fb.value))
}

private[data] trait NestedInvariantSemigroupalApply[F[_], G[_]] extends InvariantSemigroupal[Nested[F, G, ?]] {
def FG: InvariantSemigroupal[λ[α => F[G[α]]]]

def imap[A, B](fa: Nested[F, G, A])(f: A => B)(g: B => A): Nested[F, G, B] =
Nested(FG.imap(fa.value)(f)(g))

def product[A, B](fa: Nested[F, G, A], fb: Nested[F, G, B]): Nested[F, G, (A, B)] =
Nested(FG.product(fa.value, fb.value))
}
2 changes: 1 addition & 1 deletion laws/src/main/scala/cats/laws/InvariantMonoidalLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package laws
/**
* Laws that must be obeyed by any `cats.InvariantMonoidal`.
*/
trait InvariantMonoidalLaws[F[_]] extends InvariantLaws[F] with SemigroupalLaws[F] {
trait InvariantMonoidalLaws[F[_]] extends InvariantSemigroupalLaws[F] {
override implicit def F: InvariantMonoidal[F]
import cats.syntax.semigroupal._
import cats.syntax.invariant._
Expand Down
15 changes: 15 additions & 0 deletions laws/src/main/scala/cats/laws/InvariantSemigroupalLaws.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cats
package laws


/**
* Laws that are expected for any `cats.InvariantSemigroupal`.
*/
trait InvariantSemigroupalLaws[F[_]] extends InvariantLaws[F] with SemigroupalLaws[F] {
implicit override def F: InvariantSemigroupal[F]

}
object InvariantSemigroupalLaws {
def apply[F[_]](implicit ev: InvariantSemigroupal[F]): InvariantSemigroupalLaws[F] =
new InvariantSemigroupalLaws[F] { def F: InvariantSemigroupal[F] = ev }
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import cats.laws.discipline.SemigroupalTests.Isomorphisms
import org.scalacheck.{Arbitrary, Cogen}
import org.scalacheck.Prop._

trait InvariantMonoidalTests[F[_]] extends InvariantTests[F] with SemigroupalTests[F] {
trait InvariantMonoidalTests[F[_]] extends InvariantSemigroupalTests[F] {
def laws: InvariantMonoidalLaws[F]

def invariantMonoidal[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package cats
package laws
package discipline

import cats.InvariantSemigroupal
import cats.laws.discipline.SemigroupalTests.Isomorphisms
import org.scalacheck.{Arbitrary, Cogen}

trait InvariantSemigroupalTests[F[_]] extends InvariantTests[F] with SemigroupalTests[F] {
def laws: InvariantSemigroupalLaws[F]

def invariantSemigroupal[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit
arbFA: Arbitrary[F[A]],
arbFB: Arbitrary[F[B]],
arbFC: Arbitrary[F[C]],
CogenA: Cogen[A],
CogenB: Cogen[B],
CogenC: Cogen[C],
EqFA: Eq[F[A]],
EqFB: Eq[F[B]],
EqFC: Eq[F[C]],
EqFABC: Eq[F[(A, B, C)]],
iso: Isomorphisms[F]): RuleSet = new RuleSet {
val name = "invariantSemigroupal"
val parents = Seq(invariant[A, B, C], semigroupal[A, B, C])
val bases = Nil
val props = Nil
}
}

object InvariantSemigroupalTests {
def apply[F[_]: InvariantSemigroupal]: InvariantSemigroupalTests[F] =
new InvariantSemigroupalTests[F] { def laws: InvariantSemigroupalLaws[F] = InvariantSemigroupalLaws[F] }
}
4 changes: 2 additions & 2 deletions tests/src/test/scala/cats/tests/AlgebraInvariantSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package tests
import cats.Invariant
import cats.kernel._
import cats.kernel.laws.discipline.{SemigroupTests, MonoidTests, GroupTests, _}
import cats.laws.discipline.{InvariantMonoidalTests, InvariantTests, SerializableTests, SemigroupalTests}
import cats.laws.discipline.{InvariantMonoidalTests, InvariantTests, SerializableTests, InvariantSemigroupalTests}
import cats.laws.discipline.eq._
import org.scalacheck.{Arbitrary, Gen}

Expand Down Expand Up @@ -64,7 +64,7 @@ class AlgebraInvariantSuite extends CatsSuite {
checkAll("InvariantMonoidal[Semigroup]", SemigroupTests[Int](InvariantMonoidal[Semigroup].pure(0)).semigroup)
checkAll("InvariantMonoidal[CommutativeSemigroup]", CommutativeSemigroupTests[Int](InvariantMonoidal[CommutativeSemigroup].pure(0)).commutativeSemigroup)

checkAll("Semigroupal[Monoid]", SemigroupalTests[Monoid].semigroupal[Int, Int, Int])
checkAll("Semigroupal[Monoid]", InvariantSemigroupalTests[Monoid].invariantSemigroupal[Int, Int, Int])


{
Expand Down
9 changes: 5 additions & 4 deletions tests/src/test/scala/cats/tests/ListWrapper.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cats
package tests

import cats.Invariant
import cats.instances.list._
import org.scalacheck.{Arbitrary, Cogen}
import org.scalacheck.Arbitrary.arbitrary
Expand Down Expand Up @@ -43,25 +42,27 @@ object ListWrapper {

def eqv[A : Eq]: Eq[ListWrapper[A]] = Eq.by(_.list)

val traverse: Traverse[ListWrapper] = {
val traverse: Traverse[ListWrapper] with InvariantSemigroupal[ListWrapper] = {
val F = Traverse[List]

new Traverse[ListWrapper] {
new Traverse[ListWrapper] with InvariantSemigroupal[ListWrapper] {
def foldLeft[A, B](fa: ListWrapper[A], b: B)(f: (B, A) => B): B =
F.foldLeft(fa.list, b)(f)
def foldRight[A, B](fa: ListWrapper[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
F.foldRight(fa.list, lb)(f)
def traverse[G[_], A, B](fa: ListWrapper[A])(f: A => G[B])(implicit G0: Applicative[G]): G[ListWrapper[B]] = {
G0.map(F.traverse(fa.list)(f))(ListWrapper.apply)
}
def product[A, B](fa: ListWrapper[A], fb: ListWrapper[B]): ListWrapper[(A, B)] =
ListWrapper(fa.list.flatMap(a => fb.list.map(b => (a, b))))
}
}

val foldable: Foldable[ListWrapper] = traverse

val functor: Functor[ListWrapper] = traverse

val invariant: Invariant[ListWrapper] = functor
val invariant: InvariantSemigroupal[ListWrapper] = traverse

val semigroupK: SemigroupK[ListWrapper] =
new SemigroupK[ListWrapper] {
Expand Down
4 changes: 2 additions & 2 deletions tests/src/test/scala/cats/tests/MonoidSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ package tests
class MonoidSuite extends CatsSuite {
{
Invariant[Monoid]
Semigroupal[Monoid]
InvariantSemigroupal[Monoid]
}

test("companion object syntax") {
Expand All @@ -19,7 +19,7 @@ class MonoidSuite extends CatsSuite {
object MonoidSuite {
def summonInstance(): Unit = {
Invariant[Monoid]
Semigroupal[Monoid]
InvariantSemigroupal[Monoid]
()
}

Expand Down
9 changes: 9 additions & 0 deletions tests/src/test/scala/cats/tests/NestedSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ class NestedSuite extends CatsSuite {
checkAll("Contravariant[Nested[Option, Show, ?]]", SerializableTests.serializable(Contravariant[Nested[Option, Show, ?]]))
}

{
// InvariantSemigroupal + Apply functor composition
implicit val instance = ListWrapper.invariant
checkAll("Nested[ListWrapper, Option, ?]",
InvariantSemigroupalTests[Nested[ListWrapper, Option, ?]].invariantSemigroupal[Int, Int, Int])
checkAll("InvariantSemigroupal[Nested[ListWrapper, Const[String, ?], ?]",
SerializableTests.serializable(InvariantSemigroupal[Nested[ListWrapper, Option, ?]]))
}

{
// Applicative + ContravariantMonoidal functor composition
checkAll("Nested[Option, Const[String, ?], ?]",
Expand Down

0 comments on commit bd825fe

Please sign in to comment.