7
votes

I'm trying to reduce this code (scalaz 7.0.x, scala 2.10.x):

type Error[+A] = \/[String, A]
type Result[+A] = OptionT[Error, A]

into this:

type Result[+A] = OptionT[({ type λ[+α] = String \/ α })#λ, A]

And I got error "could not find implicit value for evidence parameter of type scalaz.Applicative[Main.Result]" for:

val result: Result[Int] = 42.point[Result]

Why reduced code doesn't look like the first example for scalac?

1
It seems pretty likely you're seeing this bug (although I could have sworn I've written exactly this code before).Travis Brown

1 Answers

3
votes

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.