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 InvariantSemigroupal and ability to turn Monoidals to Monoids #2088

Merged
merged 24 commits into from
Dec 18, 2017
Merged
Show file tree
Hide file tree
Changes from 9 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
95 changes: 95 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,101 @@ def mimaSettings(moduleName: String) = Seq(
exclude[DirectMissingMethodProblem]("cats.data.RWSTAlternative.sequence"),
exclude[ReversedMissingMethodProblem]("cats.MonadError.rethrow"),
exclude[ReversedMissingMethodProblem]("cats.syntax.MonadErrorSyntax.catsSyntaxMonadErrorRethrow"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.composeApply"),
exclude[DirectMissingMethodProblem]("cats.Semigroupal.catsSemigroupalForMonoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[ReversedMissingMethodProblem]("cats.ContravariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[ReversedMissingMethodProblem]("cats.Applicative.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[ReversedMissingMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[ReversedMissingMethodProblem]("cats.Apply.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantMonoidal.monoid"),
exclude[InheritedNewAbstractMethodProblem]("cats.InvariantSemigroupal.semigroup"),
exclude[ReversedMissingMethodProblem]("cats.instances.InvariantMonoidalInstances.catsSemigroupalForMonoid"),
exclude[DirectMissingMethodProblem]("cats.data.CokleisliArrow.id"),
exclude[IncompatibleResultTypeProblem]("cats.data.CokleisliArrow.id")
)
Expand Down
19 changes: 5 additions & 14 deletions core/src/main/scala/cats/Applicative.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,8 @@ import simulacrum.typeclass
*
* Must obey the laws defined in cats.laws.ApplicativeLaws.
*/
@typeclass trait Applicative[F[_]] extends Apply[F] { self =>
@typeclass trait Applicative[F[_]] extends Apply[F] with InvariantMonoidal[F] { self =>

/**
* `pure` lifts any value into the Applicative Functor.
*
* Example:
* {{{
* scala> import cats.implicits._
*
* scala> Applicative[Option].pure(10)
* res0: Option[Int] = Some(10)
* }}}
*/
def pure[A](x: A): F[A]

/**
* Returns an `F[Unit]` value, equivalent with `pure(())`.
Expand Down Expand Up @@ -184,11 +172,14 @@ import simulacrum.typeclass
*/
def whenA[A](cond: Boolean)(f: => F[A]): F[Unit] =
if (cond) void(f) else pure(())

override def monoid[A](implicit A: Monoid[A]): Monoid[F[A]] =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

every time we add a method to a trait, we break binary compatibility. Is there any reason to have this here vs the object? Can you really customize this based on the F[_]?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, maybe you are right. We had the same discussion with regards to parallel, but I think in this case it might not be as customizable.

new ApplicativeMonoid[F, A](this, A)
}

object Applicative {
def monoid[F[_], A](implicit f: Applicative[F], monoid: Monoid[A]): Monoid[F[A]] =
new ApplicativeMonoid[F, A](f, monoid)
f.monoid

/**
* Creates an applicative functor for `F`, holding domain fixed and combining
Expand Down
7 changes: 5 additions & 2 deletions core/src/main/scala/cats/Apply.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import simulacrum.typeclass
* Must obey the laws defined in cats.laws.ApplyLaws.
*/
@typeclass(excludeParents = List("ApplyArityFunctions"))
trait Apply[F[_]] extends Functor[F] with Semigroupal[F] with ApplyArityFunctions[F] { self =>
trait Apply[F[_]] extends Functor[F] with InvariantSemigroupal[F] with ApplyArityFunctions[F] { self =>

/**
* Given a value and a function in the Apply context, applies the
Expand Down Expand Up @@ -79,11 +79,14 @@ trait Apply[F[_]] extends Functor[F] with Semigroupal[F] with ApplyArityFunction
val F = self
val G = Apply[G]
}

override def semigroup[A](implicit A: Semigroup[A]): Semigroup[F[A]] =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same question about customization.

new ApplySemigroup[F, A](this, A)
}

object Apply {
def semigroup[F[_], A](implicit f: Apply[F], sg: Semigroup[A]): Semigroup[F[A]] =
new ApplySemigroup[F, A](f, sg)
f.semigroup
}

private[cats] class ApplySemigroup[F[_], A](f: Apply[F], sg: Semigroup[A]) extends Semigroup[F[A]] {
Expand Down
12 changes: 12 additions & 0 deletions core/src/main/scala/cats/Composed.scala
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,18 @@ private[cats] trait ComposedSemigroupal[F[_], G[_]] extends ContravariantSemigro
}
}

private[cats] trait ComposedInvariantApplySemigroupal[F[_], G[_]] extends InvariantSemigroupal[λ[α => F[G[α]]]] with ComposedInvariantCovariant[F, G] { outer =>
def F: InvariantSemigroupal[F]
def G: Apply[G]

def product[A, B](fa: F[G[A]], fb: F[G[B]]): F[G[(A, B)]] =
F.imap(F.product(fa, fb)) { case (ga, gb) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you plan to add tests for this instance?

G.map2(ga, gb)(_ -> _)
} { g: G[(A, B)] =>
(G.map(g)(_._1), G.map(g)(_._2))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is not tested, we might need to test an instance that is not a covariant.

}
}

private[cats] trait ComposedCovariantContravariant[F[_], G[_]] extends Contravariant[λ[α => F[G[α]]]] { outer =>
def F: Functor[F]
def G: Contravariant[G]
Expand Down
16 changes: 14 additions & 2 deletions core/src/main/scala/cats/ContravariantMonoidal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,24 @@ import simulacrum.typeclass
* 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 =>
@typeclass trait ContravariantMonoidal[F[_]] extends ContravariantSemigroupal[F] with InvariantMonoidal[F] {
/**
* `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]

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

override def monoid[A](implicit A: Monoid[A]): Monoid[F[A]] =
ContravariantMonoidal.monoid(this)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems to be breaking the previous pattern: we are calling the object from the trait, but in the other cases we call it the opposite direction.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is because we can define a ContravariantMonoidal regardless of if A is a Monoid or not.

}
object ContravariantMonoidal extends SemigroupalArityFunctions {
def monoid[F[_], A](implicit f: ContravariantMonoidal[F]): Monoid[F[A]] =
new ContravariantMonoidalMonoid[F, A](f)
}

private[cats] class ContravariantMonoidalMonoid[F[_], A](f: ContravariantMonoidal[F]) extends ContravariantSemigroupalSemigroup[F, A](f) with Monoid[F[A]] {
def empty: F[A] = f.unit
}
object ContravariantMonoidal extends SemigroupalArityFunctions
16 changes: 14 additions & 2 deletions core/src/main/scala/cats/ContravariantSemigroupal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,23 @@ import simulacrum.typeclass
* [[ContravariantSemigroupal]] is nothing more than something both contravariant
* and Semigroupal. It comes up enough to be useful, and composes well
*/
@typeclass trait ContravariantSemigroupal[F[_]] extends Semigroupal[F] with Contravariant[F] { self =>
@typeclass trait ContravariantSemigroupal[F[_]] extends InvariantSemigroupal[F] with Contravariant[F] { self =>
override def composeFunctor[G[_]: Functor]: ContravariantSemigroupal[λ[α => F[G[α]]]] =
new ComposedSemigroupal[F, G] {
def F = self
def G = Functor[G]
}

override def semigroup[A](implicit A: Semigroup[A]): Semigroup[F[A]] =
ContravariantSemigroupal.semigroup(this)
}

object ContravariantSemigroupal extends SemigroupalArityFunctions {
def semigroup[F[_], A](implicit f: ContravariantSemigroupal[F]): Semigroup[F[A]] =
new ContravariantSemigroupalSemigroup[F, A](f)
}

private[cats] class ContravariantSemigroupalSemigroup[F[_], A](f: ContravariantSemigroupal[F]) extends Semigroup[F[A]] {
def combine(a: F[A], b: F[A]): F[A] =
ContravariantSemigroupal.contramap2(a, b)((a: A) => (a, a))(f, f)
}
object ContravariantSemigroupal extends SemigroupalArityFunctions
25 changes: 24 additions & 1 deletion core/src/main/scala/cats/InvariantMonoidal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,29 @@ import simulacrum.typeclass
*
* Must obey the laws defined in cats.laws.InvariantMonoidalLaws.
*/
@typeclass trait InvariantMonoidal[F[_]] extends Invariant[F] with Semigroupal[F] {
@typeclass trait InvariantMonoidal[F[_]] extends InvariantSemigroupal[F] {
/**
* `pure` lifts any value into a Monoidal Functor.
*
* Example:
* {{{
* scala> import cats.implicits._
*
* scala> InvariantMonoidal[Option].pure(10)
* res0: Option[Int] = Some(10)
* }}}
*/
def pure[A](a: A): F[A]

/**
* Gives a `Monoid` instance if A itself has a `Monoid` instance.
*/
def monoid[A](implicit A: Monoid[A]): Monoid[F[A]] =
new InvariantMonoidalMonoid[F, A](this, A)

}


private[cats] class InvariantMonoidalMonoid[F[_], A](f: InvariantMonoidal[F], monoid: Monoid[A]) extends InvariantSemigroupalSemigroup(f, monoid) with Monoid[F[A]] {
def empty: F[A] = f.pure(monoid.empty)
}
30 changes: 30 additions & 0 deletions core/src/main/scala/cats/InvariantSemigroupal.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package cats

import simulacrum.typeclass

/**
* [[InvariantSemigroupal]] is nothing more than something both invariant
* and Semigroupal. It comes up enough to be useful, and composes well
*/
@typeclass trait InvariantSemigroupal[F[_]] extends Semigroupal[F] with Invariant[F] { self =>

def composeApply[G[_]: Apply]: InvariantSemigroupal[λ[α => F[G[α]]]] =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any plan to test cover this one as well?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has this been addressed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep!

new ComposedInvariantApplySemigroupal[F, G] {
def F = self
def G = Apply[G]
}

/**
* Gives a `Semigroup` instance if A itself has a `Semigroup` instance.
*/
def semigroup[A](implicit A: Semigroup[A]): Semigroup[F[A]] =
new InvariantSemigroupalSemigroup[F, A](this, A)

}

object InvariantSemigroupal extends SemigroupalArityFunctions

private[cats] class InvariantSemigroupalSemigroup[F[_], A](f: InvariantSemigroupal[F], sg: Semigroup[A]) extends Semigroup[F[A]] {
def combine(a: F[A], b: F[A]): F[A] =
InvariantSemigroupal.imap2(a, b)(sg.combine)(a => (a, a))(f, f)
}
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))
}
15 changes: 14 additions & 1 deletion core/src/main/scala/cats/instances/invariant.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
package cats.instances

import cats.kernel._
import cats.InvariantMonoidal
import cats.{InvariantMonoidal, Monoid, InvariantSemigroupal}

trait InvariantMonoidalInstances {

implicit def catsSemigroupalForMonoid: InvariantSemigroupal[Monoid] = new InvariantSemigroupal[Monoid] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am curious why not move these two to the companion of Monoid and Semigroup to avoid a required import?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because they're in kernel :/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh Duh

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)))
}
}

implicit val catsInvariantMonoidalSemigroup: InvariantMonoidal[Semigroup] = new InvariantMonoidal[Semigroup] {
def product[A, B](fa: Semigroup[A], fb: Semigroup[B]): Semigroup[(A, B)] = new Semigroup[(A, B)] {
def combine(x: (A, B), y: (A, B)): (A, B) = fa.combine(x._1, y._1) -> fb.combine(x._2, y._2)
Expand Down
Loading