-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Changes from 1 commit
0501b2c
3db8a82
afd8aef
d03cfd5
cdf5732
caf2a40
81e7f06
2e8c20a
a27927d
9b09aa4
1c14af2
110ac5e
f7c4104
6e7a1b5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -113,14 +113,17 @@ private[cats] trait ComposedContravariantCovariant[F[_], G[_]] extends Contravar | |
F.contramap(fga)(gb => G.map(gb)(f)) | ||
} | ||
|
||
private[cats] trait ComposedApplicativeDivisible[F[_], G[_]] extends Divisible[λ[α => F[G[α]]]] { outer => | ||
private[cats] trait ComposedApplicativeContravariantMonoidal[F[_], G[_]] extends ContravariantMonoidal[λ[α => F[G[α]]]] { outer => | ||
def F: Applicative[F] | ||
def G: Divisible[G] | ||
def G: ContravariantMonoidal[G] | ||
|
||
override def unit[A]: F[G[A]] = F.pure(G.unit) | ||
|
||
override def contramap2[A, B, C](fb: F[G[B]], fc: F[G[C]])(f: A => (B, C)): F[G[A]] = | ||
F.ap2(F.pure((gb: G[B], gc: G[C]) => G.contramap2(gb, gc)(f)))(fb, fc) | ||
override def contramap[A, B](fa: F[G[A]])(f: B => A) = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add type annotations here and for |
||
F.map(fa)(G.contramap(_)(f)) | ||
|
||
override def product[A, B](fa: F[G[A]], fb: F[G[B]]) = | ||
F.map2(fa, fb)(G.product(_,_)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need a space after the comma here :) |
||
} | ||
|
||
private[cats] trait ComposedSemigroupal[F[_], G[_]] extends ContravariantSemigroupal[λ[α => F[G[α]]]] with ComposedContravariantCovariant[F, G] { outer => | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package cats | ||
|
||
import simulacrum.typeclass | ||
|
||
/** | ||
* ContravariantMonoidal functors | ||
* | ||
* 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] | ||
|
||
def liftContravariant[A, B](f: A => B): F[B] => F[A] = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can actually be moved to |
||
contramap2(unit, _: F[B])(((b: B) => (b, b)) compose f) | ||
|
||
// Technically, this is not correct, as the Applicative is composed with the ContravariantMonoidal, not the other way around | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you mind elaborate a bit more (or point to a more detailed discussion/explanation) here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, I can also just change the name and move this possibly. The point here is mostly that I didn't want to add anything to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah, I propose we rename and move it to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it, will do. Thanks. |
||
def composeApplicative[G[_]: Applicative]: ContravariantMonoidal[λ[α => G[F[α]]]] = | ||
new ComposedApplicativeContravariantMonoidal[G, F] { | ||
val F = Applicative[G] | ||
val G = self | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,4 +12,7 @@ import simulacrum.typeclass | |
def F = self | ||
def G = Functor[G] | ||
} | ||
|
||
def contramap2[A, B, C](fb: F[B], fc: F[C])(f: A => (B, C)): F[A] = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not exactly sure if we need this definition here, as we already have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could mix in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, yes! I agree. I didn't realize they were in |
||
contramap(product(fb, fc))(f) | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -166,8 +166,8 @@ private[data] sealed abstract class KleisliInstances2 extends KleisliInstances3 | |
implicit def catsDataAlternativeForKleisli[F[_], A](implicit F0: Alternative[F]): Alternative[Kleisli[F, A, ?]] = | ||
new KleisliAlternative[F, A] { def F: Alternative[F] = F0 } | ||
|
||
implicit def catsDataDivisibleForKleisli[F[_], A](implicit F0: Divisible[F]): Divisible[Kleisli[F, A, ?]] = | ||
new KleisliDivisible[F, A] { def F: Divisible[F] = F0 } | ||
implicit def catsDataContravariantMonoidalForKleisli[F[_], A](implicit F0: ContravariantMonoidal[F]): ContravariantMonoidal[Kleisli[F, A, ?]] = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The convention in cats is that instances that are more specific should be at higher priority. I.E. instance of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gotcha, will fix. |
||
new KleisliContravariantMonoidal[F, A] { def F: ContravariantMonoidal[F] = F0 } | ||
} | ||
|
||
private[data] sealed abstract class KleisliInstances3 extends KleisliInstances4 { | ||
|
@@ -297,13 +297,16 @@ private[data] trait KleisliAlternative[F[_], A] extends Alternative[Kleisli[F, A | |
implicit def F: Alternative[F] | ||
} | ||
|
||
private[data] sealed trait KleisliDivisible[F[_], D] extends Divisible[Kleisli[F, D, ?]] { | ||
implicit def F: Divisible[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 contramap2[A, B, C](fb: Kleisli[F, D, B], fc: Kleisli[F, D, C])(f: A => (B, C)): Kleisli[F, D, A] = | ||
Kleisli(d => F.contramap2(fb.run(d), fc.run(d))(f)) | ||
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] { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn’t repeat
Monoidal
here becauseApplicative
already impliesMonoidal
since they are equivalent (see also this detailed explanation: https://stackoverflow.com/questions/23316255/lax-monoidal-functors-with-a-different-monoidal-structure).Edit: sorry I was wrong. This trait composes a covariant applicative with a contravariant one, so the naming is correct, you can ignore my comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The SO was a good read, anyway, it clarified some of the points on different
Monoidal
structures for me, so thank you.