Implicit resolution of lambda types seems broken. Apparently the compiler first desugars the the type and then mismatches on the number of type parameters.
A 'simplified' example:
Defining a monad and two traits. One
is similar to Either
. Two
is similar to EitherT
trait Monad[F[_]]
trait One[A, B]
object One {
implicit def m[A]: Monad[({ type T[x] = One[A, x] })#T] = ???
}
trait Two[F[_], A]
object Two {
implicit def m[F[_]]: Monad[({ type T[x] = Two[F, x] })#T] = ???
}
Defining a type alias and a case class to partially apply One
with String
as it's first parameter. The case class version can be used as a workaround.
type OneX[A] = One[String, A]
case class OneY[A](value: OneX[A])
object OneY {
implicit def m(implicit ev: Monad[OneX]): Monad[OneY] = ???
}
Implicit resolution of all 'simple' types works.
implicitly[Monad[OneX]]
implicitly[Monad[({ type T[x] = One[String, x] })#T]]
implicitly[Monad[OneY]]
Defining several type aliases that partially apply Two
type TwoX[A] = Two[OneX, A]
type TwoY[A] = Two[({ type T[x] = One[String, x] })#T, A]
type TwoZ[A] = Two[OneY, A]
Here we see that the one using the lambda type fails.
implicitly[Monad[TwoX]]
implicitly[Monad[TwoY]] // fails
implicitly[Monad[TwoZ]]
Here we see that all lambda types that use a type alias fail. Only the one that actually refers to a stable type with a single parameter succeeds.
implicitly[Monad[({ type T[x] = Two[OneX, x] })#T]] // fails
implicitly[Monad[({ type T[x] = Two[OneY, x] })#T]]
implicitly[Monad[({ type T[x] = Two[({ type T[x] = One[String, x] })#T, x] })#T]] //fails
My knowledge about the compiler is fairly limited and this might be related to the bug @TravisBrown points to.