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

EitherT[Option, ?, ?]] can't be used as a bifunctor #4569

Closed
strokyl opened this issue Feb 27, 2024 · 5 comments · Fixed by #4576
Closed

EitherT[Option, ?, ?]] can't be used as a bifunctor #4569

strokyl opened this issue Feb 27, 2024 · 5 comments · Fixed by #4576

Comments

@strokyl
Copy link

strokyl commented Feb 27, 2024

With scala 2.13.12
and cats-core 2.10.0

  type MyBifunctor[A, B] = EitherT[Option, A, B]
  val myByFunctor = implicitly[Bifunctor[MyBifunctor]]

Does not compile :

ambiguous implicit values:
 both method catsDataBitraverseForEitherT in class EitherTInstances1 of type [F[_]](implicit F: cats.Traverse[F]): cats.Bitraverse[[β$69$, γ$70$]cats.data.EitherT[F,β$69$,γ$70$]]
 and method catsDataBifunctorForEitherT in class EitherTInstances of type [F[_]](implicit F: cats.Functor[F]): cats.Bifunctor[[β$15$, γ$16$]cats.data.EitherT[F,β$15$,γ$16$]]
 match expected type cats.Bifunctor[A.MyBifunctor] [25:21]

And unfortunately both:

  • catsDataBifunctorForEitherT
  • catsDataBitraverseForEitherT

are private so I can't provide one explicitly.

I found that issue trying to understand why I could do a leftWiden on :
EitherT[IO, ?, ?] and not on EitherT[Option, ?, ?]

@armanbilge
Copy link
Member

are private so I can't provide one explicitly.

Actually they are both public. Implicits have to be public to work at all. How did you try using them, what is the compiler error?

@armanbilge
Copy link
Member

EitherT[IO, ?, ?]

See also a discussion here about why you should not use EitherT and other monad transformers with IO.

@satorg
Copy link
Contributor

satorg commented Feb 27, 2024

Yes, there is a conflict indeed among implicits. The problem is that there are both catsDataBifunctorForEitherT and catsDataBitraverseForEitherT implicits available:

implicit def catsDataBifunctorForEitherT[F[_]](implicit F: Functor[F]): Bifunctor[EitherT[F, *, *]]
implicit def catsDataBitraverseForEitherT[F[_]](implicit F: Traverse[F]): Bitraverse[EitherT[F, *, *]]

Consequently, the first one requires Functor for F whereas the second one – Traverse.
However, there are both implementations available for Option:

// Invariant.scala
implicit def catsInstancesForOption: MonadError[Option, Unit] with Alternative[Option] with CoflatMap[Option] with CommutativeMonad[Option]
// UnorderedFoldable.scala
implicit def catsTraverseForOption: Traverse[Option]

Therefore, Scala cannot choose which one to pick up.

And it is not just for Option, e.g. List has the same issue:

val bifunET = Bifunctor[EitherT[List, *, *]]

ambiguous implicit values:
 both method catsDataBitraverseForEitherT in class EitherTInstances1 of type [F[_]](implicit F: cats.Traverse[F]): cats.Bitraverse[[β$69$, γ$70$]cats.data.EitherT[F,β$69$,γ$70$]]
 and method catsDataBifunctorForEitherT in class EitherTInstances of type [F[_]](implicit F: cats.Functor[F]): cats.Bifunctor[[β$15$, γ$16$]cats.data.EitherT[F,β$15$,γ$16$]]
 match expected type cats.Bifunctor[[β$2$, γ$3$]cats.data.EitherT[[+A]List[A],β$2$,γ$3$]]
  val bifunET = Bifunctor[EitherT[List, *, *]]

☝️ This is for Scala 2.13.13.

@joroKr21
Copy link
Member

The issue is that the priorities are swapped. Bitraverse is a subtype of Bifunctor but catsDataBitraverseForEitherT is defined in a supertype of catsDataBifunctorForEitherT. You can move catsDataBitraverseForEitherT to EitherTInstances to fix that.

@strokyl
Copy link
Author

strokyl commented Feb 28, 2024

are private so I can't provide one explicitly.

Actually they are both public. Implicits have to be public to work at all. How did you try using them, what is the compiler error?

Sorry you right I was tricked because there were defined in a abstract package private class that is later extended by EitherT.
One can import:

import EitherT.catsDataBifunctorForEitherT

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants