typelevel / cats

Lightweight, modular, and extensible library for functional programming.

Home Page:https://typelevel.org/cats/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

strokyl opened this issue · comments

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, ?, ?]

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?

EitherT[IO, ?, ?]

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

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.

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.

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