Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ContravariantMonoidal #2034

Merged
merged 14 commits into from
Dec 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,40 @@ def mimaSettings(moduleName: String) = Seq(
exclude[MissingTypesProblem]("cats.data.OneAndLowPriority3"),
exclude[MissingTypesProblem]("cats.data.OneAndLowPriority2"),
exclude[MissingTypesProblem]("cats.data.OneAndLowPriority1"),
exclude[ReversedMissingMethodProblem]("cats.Contravariant.liftContravariant"),
exclude[DirectMissingMethodProblem]("cats.implicits.catsContravariantSemigroupalForEq"),
exclude[DirectMissingMethodProblem]("cats.implicits.catsContravariantSemigroupalForOrder"),
exclude[DirectMissingMethodProblem]("cats.implicits.catsContravariantSemigroupalForOrdering"),
exclude[DirectMissingMethodProblem]("cats.implicits.catsContravariantSemigroupalEquiv"),
exclude[ReversedMissingMethodProblem]("cats.ContravariantSemigroupal.contramap2"),
exclude[ReversedMissingMethodProblem]("cats.ContravariantSemigroupal#Ops.contramap2"),
exclude[InheritedNewAbstractMethodProblem]("cats.ContravariantMonoidal#ToContravariantMonoidalOps.toContravariantMonoidalOps"),
exclude[InheritedNewAbstractMethodProblem]("cats.ContravariantSemigroupal#ToContravariantSemigroupalOps.toContravariantSemigroupalOps"),
exclude[ReversedMissingMethodProblem]("cats.Applicative.composeContravariantMonoidal"),
exclude[UpdateForwarderBodyProblem]("cats.instances.Function1Instances.catsStdContravariantForFunction1"),
exclude[DirectMissingMethodProblem]("cats.instances.package=uiv.catsContravariantSemigroupalEquiv"),
exclude[DirectMissingMethodProblem]("cats.instances.OrderingInstances.catsContravariantSemigroupalForOrdering"),
exclude[ReversedMissingMethodProblem]("cats.instances.OrderingInstances.cats$instances$OrderingInstances$_setter_$catsContravariantMonoidalForOrdering_="),
exclude[ReversedMissingMethodProblem]("cats.instances.OrderingInstances.catsContravariantMonoidalForOrdering"),
exclude[DirectMissingMethodProblem]("cats.instances.OrderInstances.catsContravariantSemigroupalForOrder"),
exclude[ReversedMissingMethodProblem]("cats.instances.OrderInstances.catsContravariantMonoidalForOrder"),
exclude[ReversedMissingMethodProblem]("cats.instances.OrderInstances.cats$instances$OrderInstances$_setter_$catsContravariantMonoidalForOrder_="),
exclude[DirectMissingMethodProblem]("cats.instances.package#ordering.catsContravariantSemigroupalForOrdering"),
exclude[DirectMissingMethodProblem]("cats.instances.package#all.catsContravariantSemigroupalForEq"),
exclude[DirectMissingMethodProblem]("cats.instances.package#all.catsContravariantSemigroupalForOrder"),
exclude[DirectMissingMethodProblem]("cats.instances.package#all.catsContravariantSemigroupalForOrdering"),
exclude[DirectMissingMethodProblem]("cats.instances.package#all.catsContravariantSemigroupalEquiv"),
exclude[DirectMissingMethodProblem]("cats.instances.EquivInstances.catsContravariantSemigroupalEquiv"),
exclude[ReversedMissingMethodProblem]("cats.instances.EquivInstances.catsContravariantMonoidalForEquiv"),
exclude[ReversedMissingMethodProblem]("cats.instances.EquivInstances.cats$instances$EquivInstances$_setter_$catsContravariantMonoidalForEquiv_="),
exclude[DirectMissingMethodProblem]("cats.instances.package=.catsContravariantSemigroupalForEq"),
exclude[DirectMissingMethodProblem]("cats.instances.package#order.catsContravariantSemigroupalForOrder"),
exclude[ReversedMissingMethodProblem]("cats.instances.Function1Instances.catsStdContravariantMonoidalForFunction1"),
exclude[DirectMissingMethodProblem]("cats.instances.EqInstances.catsContravariantSemigroupalForEq"),
exclude[ReversedMissingMethodProblem]("cats.instances.EqInstances.catsContravariantMonoidalForEq"),
exclude[ReversedMissingMethodProblem]("cats.instances.EqInstances.cats$instances$EqInstances$_setter_$catsContravariantMonoidalForEq_="),
exclude[InheritedNewAbstractMethodProblem]("cats.syntax.ContravariantSemigroupalSyntax.catsSyntaxContravariantSemigroupal"),
exclude[InheritedNewAbstractMethodProblem]("cats.syntax.ContravariantMonoidalSyntax.catsSyntaxContravariantMonoidal"),
exclude[DirectMissingMethodProblem]("cats.data.OneAndLowPriority3.catsDataNonEmptyTraverseForOneAnd"),
exclude[DirectMissingMethodProblem]("cats.data.OneAndLowPriority2.catsDataTraverseForOneAnd"),
exclude[ReversedMissingMethodProblem]("cats.instances.ParallelInstances.catsStdNonEmptyParallelForZipVector"),
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/scala/cats/Applicative.scala
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ import simulacrum.typeclass
val G = Applicative[G]
}

def composeContravariantMonoidal[G[_]: ContravariantMonoidal]: ContravariantMonoidal[λ[α => F[G[α]]]] =
new ComposedApplicativeContravariantMonoidal[F, G] {
val F = self
val G = ContravariantMonoidal[G]
}

/**
* Returns the given argument if `cond` is `false`, otherwise, unit lifted into F.
*/
Expand Down
13 changes: 13 additions & 0 deletions core/src/main/scala/cats/Composed.scala
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,19 @@ private[cats] trait ComposedContravariantCovariant[F[_], G[_]] extends Contravar
F.contramap(fga)(gb => G.map(gb)(f))
}

private[cats] trait ComposedApplicativeContravariantMonoidal[F[_], G[_]] extends ContravariantMonoidal[λ[α => F[G[α]]]] { outer =>
def F: Applicative[F]
def G: ContravariantMonoidal[G]

override def unit[A]: F[G[A]] = F.pure(G.unit)

override def contramap[A, B](fa: F[G[A]])(f: B => A): F[G[B]] =
F.map(fa)(G.contramap(_)(f))

override def product[A, B](fa: F[G[A]], fb: F[G[B]]): F[G[(A, B)]] =
F.map2(fa, fb)(G.product(_, _))
}

private[cats] trait ComposedSemigroupal[F[_], G[_]] extends ContravariantSemigroupal[λ[α => F[G[α]]]] with ComposedContravariantCovariant[F, G] { outer =>
def F: ContravariantSemigroupal[F]
def G: Functor[G]
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/scala/cats/Contravariant.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import simulacrum.typeclass
*/
def narrow[A, B <: A](fa: F[A]): F[B] = fa.asInstanceOf[F[B]]

def liftContravariant[A, B](f: A => B): F[B] => F[A] = contramap(_: F[B])(f)

override def composeFunctor[G[_]: Functor]: Contravariant[λ[α => F[G[α]]]] =
new ComposedContravariantCovariant[F, G] {
val F = self
Expand Down
22 changes: 22 additions & 0 deletions core/src/main/scala/cats/ContravariantMonoidal.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package cats

import simulacrum.typeclass

/**
* [[ContravariantMonoidal]] functors are functors that supply
* a unit along the diagonal map for the `contramap2` operation.
*
* Must obey the laws defined in cats.laws.ContravariantMonoidalLaws.
*
* Based on ekmett's contravariant library:
* https://hackage.haskell.org/package/contravariant-1.4/docs/Data-Functor-Contravariant-Divisible.html
*/
@typeclass trait ContravariantMonoidal[F[_]] extends ContravariantSemigroupal[F] { self =>
/**
* `unit` produces an instance of `F` for any type `A`
* that is trivial with respect to `contramap2` along
* the diagonal
*/
def unit[A]: F[A]
}
object ContravariantMonoidal extends SemigroupalArityFunctions
1 change: 1 addition & 0 deletions core/src/main/scala/cats/ContravariantSemigroupal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ import simulacrum.typeclass
def G = Functor[G]
}
}
object ContravariantSemigroupal extends SemigroupalArityFunctions
13 changes: 10 additions & 3 deletions core/src/main/scala/cats/data/Const.scala
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,12 @@ private[data] sealed abstract class ConstInstances extends ConstInstances0 {
def show(f: Const[A, B]): String = f.show
}

implicit def catsDataContravariantForConst[C]: Contravariant[Const[C, ?]] = new Contravariant[Const[C, ?]] {
override def contramap[A, B](fa: Const[C, A])(f: (B) => A): Const[C, B] =
implicit def catsDataContravariantMonoidalForConst[D: Monoid]: ContravariantMonoidal[Const[D, ?]] = new ContravariantMonoidal[Const[D, ?]] {
override def unit[A] = Const.empty[D, A]
override def contramap[A, B](fa: Const[D, A])(f: B => A): Const[D, B] =
fa.retag[B]
override def product[A, B](fa: Const[D, A], fb: Const[D, B]): Const[D, (A, B)] =
fa.retag[(A, B)] combine fb.retag[(A, B)]
}

implicit def catsDataTraverseForConst[C]: Traverse[Const[C, ?]] = new Traverse[Const[C, ?]] {
Expand Down Expand Up @@ -102,11 +105,15 @@ private[data] sealed abstract class ConstInstances extends ConstInstances0 {
}

private[data] sealed abstract class ConstInstances0 extends ConstInstances1 {

implicit def catsDataSemigroupForConst[A: Semigroup, B]: Semigroup[Const[A, B]] = new Semigroup[Const[A, B]] {
def combine(x: Const[A, B], y: Const[A, B]): Const[A, B] = x combine y
}

implicit def catsDataContravariantForConst[C]: Contravariant[Const[C, ?]] = new Contravariant[Const[C, ?]] {
override def contramap[A, B](fa: Const[C, A])(f: (B) => A): Const[C, B] =
fa.retag[B]
}

implicit def catsDataPartialOrderForConst[A: PartialOrder, B]: PartialOrder[Const[A, B]] = new PartialOrder[Const[A, B]]{
def partialCompare(x: Const[A, B], y: Const[A, B]): Double =
x partialCompare y
Expand Down
19 changes: 18 additions & 1 deletion core/src/main/scala/cats/data/IdT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@ private[data] sealed trait IdTApplicative[F[_]] extends Applicative[IdT[F, ?]] w
def pure[A](a: A): IdT[F, A] = IdT.pure(a)
}

private[data] sealed trait IdTContravariantMonoidal[F[_]] extends ContravariantMonoidal[IdT[F, ?]] {
implicit val F0: ContravariantMonoidal[F]

override def unit[A]: IdT[F, A] = IdT(F0.unit[A])

override def contramap[A, B](fa: IdT[F, A])(f: B => A): IdT[F, B] =
IdT(F0.contramap(fa.value)(f))

override def product[A, B](fa: IdT[F, A], fb: IdT[F, B]): IdT[F, (A, B)] =
IdT(F0.product(fa.value, fb.value))
}

private[data] sealed trait IdTFlatMap[F[_]] extends FlatMap[IdT[F, ?]] with IdTApply[F] {
implicit val F0: FlatMap[F]

Expand Down Expand Up @@ -123,7 +135,12 @@ private[data] sealed trait IdTNonEmptyTraverse[F[_]] extends IdTTraverse[F] with
fa.reduceRightTo(f)(g)
}

private[data] sealed abstract class IdTInstances5 {
private[data] sealed abstract class IdTInstances6 {
implicit def catsDataContravariantMonoidalForIdT[F[_]](implicit F: ContravariantMonoidal[F]): ContravariantMonoidal[IdT[F, ?]] =
new IdTContravariantMonoidal[F] { implicit val F0: ContravariantMonoidal[F] = F }
}

private[data] sealed abstract class IdTInstances5 extends IdTInstances6 {
implicit def catsDataFunctorForIdT[F[_]](implicit F: Functor[F]): Functor[IdT[F, ?]] =
new IdTFunctor[F] { implicit val F0: Functor[F] = F }
}
Expand Down
26 changes: 26 additions & 0 deletions core/src/main/scala/cats/data/IndexedStateT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,10 @@ private[data] sealed abstract class IndexedStateTInstances extends IndexedStateT
implicit def catsDataAlternativeForIndexedStateT[F[_], S](implicit FM: Monad[F],
FA: Alternative[F]): Alternative[IndexedStateT[F, S, S, ?]] with Monad[IndexedStateT[F, S, S, ?]] =
new IndexedStateTAlternative[F, S] { implicit def F = FM; implicit def G = FA }

implicit def catsDataContravariantMonoidalForIndexedStateT[F[_], S](implicit FD: ContravariantMonoidal[F],
FA: Applicative[F]): ContravariantMonoidal[IndexedStateT[F, S, S, ?]] =
new IndexedStateTContravariantMonoidal[F, S] { implicit def F = FD; implicit def G = FA }
}

private[data] sealed abstract class IndexedStateTInstances1 extends IndexedStateTInstances2 {
Expand Down Expand Up @@ -362,6 +366,28 @@ private[data] sealed abstract class IndexedStateTSemigroupK[F[_], SA, SB] extend
IndexedStateT(s => G.combineK(x.run(s), y.run(s)))
}

private[data] sealed abstract class IndexedStateTContravariantMonoidal[F[_], S] extends ContravariantMonoidal[IndexedStateT[F, S, S, ?]]{
implicit def F: ContravariantMonoidal[F]
implicit def G: Applicative[F]

override def unit[A]: IndexedStateT[F, S, S, A] =
IndexedStateT.applyF(G.pure((s: S) => F.unit[(S, A)]))

override def contramap[A, B](fa: IndexedStateT[F, S, S, A])(f: B => A): IndexedStateT[F, S, S, B] =
contramap2(fa, unit)(((a: A) => (a, a)) compose f)

override def product[A, B](fa: IndexedStateT[F, S, S, A], fb: IndexedStateT[F, S, S, B]): IndexedStateT[F, S, S, (A, B)] =
contramap2(fa, fb)(identity)

def contramap2[A, B, C](fb: IndexedStateT[F, S, S, B], fc: IndexedStateT[F, S, S, C])(f: A => (B, C)): IndexedStateT[F, S, S, A] =
IndexedStateT.applyF(
G.pure((s: S) =>
ContravariantMonoidal.contramap2(G.map(fb.runF)(_.apply(s)), G.map(fc.runF)(_.apply(s)))(
(tup: (S, A)) => f(tup._2) match {
case (b, c) => (G.pure((tup._1, b)), G.pure((tup._1, c)))
})(G, F)))
}

private[data] sealed abstract class IndexedStateTAlternative[F[_], S] extends IndexedStateTMonad[F, S] with Alternative[IndexedStateT[F, S, S, ?]] {
def G: Alternative[F]

Expand Down
25 changes: 20 additions & 5 deletions core/src/main/scala/cats/data/Kleisli.scala
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,8 @@ private[data] sealed abstract class KleisliInstances0 extends KleisliInstances1
implicit val catsDataCommutativeArrowForKleisliId: CommutativeArrow[Kleisli[Id, ?, ?]] =
catsDataCommutativeArrowForKleisli[Id]

implicit def catsDataContravariantForKleisli[F[_], C]: Contravariant[Kleisli[F, ?, C]] =
new Contravariant[Kleisli[F, ?, C]] {
override def contramap[A, B](fa: Kleisli[F, A, C])(f: B => A): Kleisli[F, B, C] =
fa.local(f)
}
implicit def catsDataContravariantMonoidalForKleisli[F[_], A](implicit F0: ContravariantMonoidal[F]): ContravariantMonoidal[Kleisli[F, A, ?]] =
new KleisliContravariantMonoidal[F, A] { def F: ContravariantMonoidal[F] = F0 }
}

private[data] sealed abstract class KleisliInstances1 extends KleisliInstances2 {
Expand All @@ -160,6 +157,12 @@ private[data] sealed abstract class KleisliInstances1 extends KleisliInstances2
def parallel: Kleisli[M, A, ?] ~> Kleisli[F, A, ?] =
λ[Kleisli[M, A, ?] ~> Kleisli[F, A, ?]](_.mapK(P.parallel))
}

implicit def catsDataContravariantForKleisli[F[_], C]: Contravariant[Kleisli[F, ?, C]] =
new Contravariant[Kleisli[F, ?, C]] {
override def contramap[A, B](fa: Kleisli[F, A, C])(f: B => A): Kleisli[F, B, C] =
fa.local(f)
}
}

private[data] sealed abstract class KleisliInstances2 extends KleisliInstances3 {
Expand Down Expand Up @@ -294,6 +297,18 @@ private[data] trait KleisliAlternative[F[_], A] extends Alternative[Kleisli[F, A
implicit def F: Alternative[F]
}

private[data] sealed trait KleisliContravariantMonoidal[F[_], D] extends ContravariantMonoidal[Kleisli[F, D, ?]] {
implicit def F: ContravariantMonoidal[F]

override def unit[A]: Kleisli[F, D, A] = Kleisli(Function.const(F.unit[A]))

override def contramap[A, B](fa: Kleisli[F, D, A])(f: B => A): Kleisli[F, D, B] =
Kleisli(d => F.contramap(fa.run(d))(f))

override def product[A, B](fa: Kleisli[F, D, A], fb: Kleisli[F, D, B]): Kleisli[F, D, (A, B)] =
Kleisli(d => F.product(fa.run(d), fb.run(d)))
}

private[data] trait KleisliMonadError[F[_], A, E] extends MonadError[Kleisli[F, A, ?], E] with KleisliApplicativeError[F, A, E] with KleisliMonad[F, A] {
def F: MonadError[F, E]
}
Expand Down
17 changes: 17 additions & 0 deletions core/src/main/scala/cats/data/Nested.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ private[data] sealed abstract class NestedInstances extends NestedInstances0 {
new NestedNonEmptyTraverse[F, G] {
val FG: NonEmptyTraverse[λ[α => F[G[α]]]] = NonEmptyTraverse[F].compose[G]
}

implicit def catsDataContravariantMonoidalForApplicativeForNested[F[_]: Applicative, G[_]: ContravariantMonoidal]: ContravariantMonoidal[Nested[F, G, ?]] =
new NestedContravariantMonoidal[F, G] {
val FG: ContravariantMonoidal[λ[α => F[G[α]]]] = Applicative[F].composeContravariantMonoidal[G]
}
}

private[data] sealed abstract class NestedInstances0 extends NestedInstances1 {
Expand Down Expand Up @@ -263,3 +268,15 @@ private[data] trait NestedContravariant[F[_], G[_]] extends Contravariant[Nested
def contramap[A, B](fga: Nested[F, G, A])(f: B => A): Nested[F, G, B] =
Nested(FG.contramap(fga.value)(f))
}

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

def unit[A]: Nested[F, G, A] = Nested(FG.unit)

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

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))
}
20 changes: 20 additions & 0 deletions core/src/main/scala/cats/data/OptionT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ private[data] sealed abstract class OptionTInstances0 extends OptionTInstances1
implicit def catsDataMonadErrorForOptionT[F[_], E](implicit F0: MonadError[F, E]): MonadError[OptionT[F, ?], E] =
new OptionTMonadError[F, E] { implicit val F = F0 }

implicit def catsDataContravariantMonoidalForOptionT[F[_]](implicit F0: ContravariantMonoidal[F]): ContravariantMonoidal[OptionT[F, ?]] =
new OptionTContravariantMonoidal[F] { implicit val F = F0 }

implicit def catsDataSemigroupKForOptionT[F[_]](implicit F0: Monad[F]): SemigroupK[OptionT[F, ?]] =
new OptionTSemigroupK[F] { implicit val F = F0 }

Expand Down Expand Up @@ -281,6 +284,23 @@ private trait OptionTMonadError[F[_], E] extends MonadError[OptionT[F, ?], E] wi
OptionT(F.handleErrorWith(fa.value)(f(_).value))
}

private trait OptionTContravariantMonoidal[F[_]] extends ContravariantMonoidal[OptionT[F, ?]] {
def F: ContravariantMonoidal[F]

override def unit[A]: OptionT[F, A] = OptionT (F.unit)

override def contramap[A, B](fa: OptionT[F, A])(f: B => A): OptionT[F, B] =
OptionT(F.contramap(fa.value)(_ map f))

override def product[A, B](fa: OptionT[F, A], fb: OptionT[F, B]): OptionT[F, (A, B)] =
OptionT(F.contramap(F.product(fa.value, fb.value))(
(t: Option[(A, B)]) => t match {
case Some((x, y)) => (Some(x), Some(y))
case None => (None, None)
}
))
}

private[data] trait OptionTFoldable[F[_]] extends Foldable[OptionT[F, ?]] {
implicit def F: Foldable[F]

Expand Down
23 changes: 19 additions & 4 deletions core/src/main/scala/cats/data/Tuple2K.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,22 @@ private[data] sealed abstract class Tuple2KInstances extends Tuple2KInstances0 {
def F: Show[F[A]] = FF
def G: Show[G[A]] = GF
}
implicit def catsDataContravariantForTuple2K[F[_], G[_]](implicit FC: Contravariant[F], GC: Contravariant[G]): Contravariant[λ[α => Tuple2K[F, G, α]]] = new Tuple2KContravariant[F, G] {
def F: Contravariant[F] = FC
def G: Contravariant[G] = GC
}
implicit def catsDataContravariantMonoidalForTuple2k[F[_], G[_]](implicit FD: ContravariantMonoidal[F], GD: ContravariantMonoidal[G]): ContravariantMonoidal[λ[α => Tuple2K[F, G, α]]] =
new Tuple2KContravariantMonoidal[F, G] {
def F: ContravariantMonoidal[F] = FD
def G: ContravariantMonoidal[G] = GD
}
}

private[data] sealed abstract class Tuple2KInstances0 extends Tuple2KInstances1 {
implicit def catsDataTraverseForTuple2K[F[_], G[_]](implicit FF: Traverse[F], GF: Traverse[G]): Traverse[λ[α => Tuple2K[F, G, α]]] = new Tuple2KTraverse[F, G] {
def F: Traverse[F] = FF
def G: Traverse[G] = GF
}
implicit def catsDataContravariantForTuple2K[F[_], G[_]](implicit FC: Contravariant[F], GC: Contravariant[G]): Contravariant[λ[α => Tuple2K[F, G, α]]] = new Tuple2KContravariant[F, G] {
def F: Contravariant[F] = FC
def G: Contravariant[G] = GC
}
implicit def catsDataEqForTuple2K[F[_], G[_], A](implicit FF: Eq[F[A]], GG: Eq[G[A]]): Eq[Tuple2K[F, G, A]] = new Eq[Tuple2K[F, G, A]] {
def eqv(x: Tuple2K[F, G, A], y: Tuple2K[F, G, A]): Boolean =
FF.eqv(x.first, y.first) && GG.eqv(x.second, y.second)
Expand Down Expand Up @@ -123,6 +128,16 @@ private[data] sealed trait Tuple2KContravariant[F[_], G[_]] extends Contravarian
def contramap[A, B](fa: Tuple2K[F, G, A])(f: B => A): Tuple2K[F, G, B] = Tuple2K(F.contramap(fa.first)(f), G.contramap(fa.second)(f))
}

private[data] sealed trait Tuple2KContravariantMonoidal[F[_], G[_]] extends ContravariantMonoidal[λ[α => Tuple2K[F, G, α]]] {
def F: ContravariantMonoidal[F]
def G: ContravariantMonoidal[G]
def unit[A]: Tuple2K[F, G, A] = Tuple2K(F.unit, G.unit)
def product[A, B](fa: Tuple2K[F, G, A], fb: Tuple2K[F, G, B]): Tuple2K[F, G, (A, B)] =
Tuple2K(F.product(fa.first, fb.first), G.product(fa.second, fb.second))
def contramap[A, B](fa: Tuple2K[F, G, A])(f: B => A): Tuple2K[F, G, B] =
Tuple2K(F.contramap(fa.first)(f), G.contramap(fa.second)(f))
}

private[data] sealed trait Tuple2KApply[F[_], G[_]] extends Apply[λ[α => Tuple2K[F, G, α]]] with Tuple2KFunctor[F, G] {
def F: Apply[F]
def G: Apply[G]
Expand Down
Loading