Closed tmccarthy closed 3 years ago
Yeah the variance problem isn't nice. It also creates a mess when you're trying to use the classes in a tagless style. You generally need F[+_, +_]: Sync
instead of the nicer F[_, _]: Sync
.
I might have a try at making the entire class hierarchy invariant in both type parameters, and add utility methods for the common widening operations. I'll do it on a branch and see what it looks like. I can't think of another way to define instances for EitherT
.
Yes. On the bright side, however, not having to explicitly widen reduces the noise. Wartremover is getting upset however, I have to disable Wart.JavaSerializable, Wart.Product, Wart.Serializable, Wart.Any.
Seems I'm kind of stuck now without indeed an invariant hierarchy. How about unchecked variance? Unfortunately, the snippet below doesn't work, but maybe you would know a way around it?
class BifunctorMonadInstance[F[_]](implicit monad: Monad[F])
extends BifunctorInstance[F]
with BifunctorMonad[EitherT[F, * @uncheckedVariance, * @uncheckedVariance]]
Yeah, kind-projector
struggles with unchecked variance. You'd have to create a dedicated type alias like:
type UncheckedEitherT[F[_], A, B] = EitherT[F, A @uncheckedVariance, B @uncheckedVariance]
See example. I'm not sure if the implicit resolution would still work though. I'd be interested to see if this is successful. Please feel free to submit a PR, even if it's just to demonstrate what these EitherT
instances would roughly look like.
I've tried. No luck.
With this:
type CovariantEitherT[F[_], +A, +B] = EitherT[F, A @uncheckedVariance, B @uncheckedVariance]
The declaration
class BifunctorMonadInstance[F[_]](implicit monad: Monad[F])
extends BifunctorInstance[F]
with BifunctorMonad[CovariantEitherT[F, +*, +*]]
Still gives me
covariant type β$2$ occurs in invariant position in type [+β$2$, +γ$3$]cats.data.EitherT[F,β$2$,γ$3$] of value <local Λ$> with BifunctorMonad[CovariantEitherT[F, +*, +*]] {
If I do
class BifunctorMonadInstance[F[_]](implicit monad: Monad[F])
extends BifunctorInstance[F]
with BifunctorMonad[CovariantEitherT[F, *, *]]
funnily enough, I get
[β$2$, γ$3$]cats.data.EitherT[F,β$2$,γ$3$]'s type parameters do not match type F's expected parameters: type β$2$ is invariant, but type _ is declared covariant, type γ$3$ is invariant, but type _ is declared covariant with BifunctorMonad[CovariantEitherT[F, *, *]]
looks like the compiler is contradicting itself 😉
Yeah this is very frustrating. The @uncheckedVariance
trick should work, and in fact it does work in Scala 2.12
. It looks like there's a compiler bug. The following compiles for me in 2.12.12
, but not in 2.13.4
:
implicit def standardInstances[F[_] : cats.Monad]: BifunctorMonad[({type L[@uncheckedVariance +X, @uncheckedVariance +Y] = cats.data.EitherT[F, X @uncheckedVariance, Y @uncheckedVariance] @uncheckedVariance})#L @uncheckedVariance] =
???
As you can see I've put @uncheckedVariance
everywhere in the hope that it might work. 😐
There were some issues introduced in 2.13.2
that broke @uncheckedVariance
in higher-kinded types (see bugs), but I think these seem to have been fixed in 2.13.3
? I might have to raise an issue 😕.
Interesting, yeah seems like this is on the fringe and regularly gets broken. That wouldn't be needed with your new invariant branch, however, right? how is it going, do you need any help?
Yes, but unfortunately I'm having other issues with the invariant branch 😅. The implicit conversions for the Ops
traits are coming up against another compiler bug causing issues where either type parameter is Nothing
, which is a common scenario for this project. I believe I can find a way around it though. Feel free to raise any PRs against the invariant-type-parameters
branch. I'll hopefully have some time to work on it this coming weekend.
@jchapuis I've merged the invariant type parameters branch, and am working on instances for EitherT
on cats-eithert-instances
. Should have something released before Christmas.
This is great, thanks a lot 🎅 ! Just to show a sign that I care, I created this tiny PR yesterday night https://github.com/tmccarthy/bfect/pull/16 but feel free to ignore 😄
@jchapuis I've released 0.4.0
, which makes instances for EitherT
available with either of the following imports:
import au.id.tmm.bfect.interop.cats.instances.eitherT._
// OR
import au.id.tmm.bfect.interop.cats.implicits._
Let me know if you run into any issues!
Turns out I stuffed up the publishing for 0.4.0
. Should be all good in 0.4.1
.
awesome thanks!
Hi there, I was just writing this below, but I'm now running into a variance problem as
BifunctorMonad
has covariant parameters while cat'sEitherT
doesn't. Any suggestions?Btw. my domain looks great using
Bifunctor
, it reduced a lot of the noise associated withEitherT
. Now have to figure a way to make it run 😉