Fabian Schmitthenner
Fabian Schmitthenner

Reputation: 1706

why do implicits not trigger in this type dependent paths scenario

Let's say I define some type in a trait, that should implement some type class (like functor):

import cats.Functor
import cats.syntax.functor.toFunctorOps

trait Library {
  type T[+A]
  implicit val isFunctor: Functor[T]
}

Now, I want to use this library. The following works fine:

trait LibraryUser {

  val l: Library
  import l._

  def use: T[Boolean] = {
    val t: T[Int] = ???
    t.map(_ => true)
  }
}

But when using it in a method with a parameter instead, the import of the implicit isn't working (out commented line doesn't compile) and you have to write the implicit for yourself instead:

object LibraryUser1 {
  def use(l: Library): l.T[Boolean] = {
    import l._

    val t: T[Int] = ???
    //t.map(_ => true)
    toFunctorOps(t)(isFunctor).map(_ => true)
  }
}

Why is this the case / what can be done against it.

Upvotes: 2

Views: 64

Answers (1)

Michael Zajac
Michael Zajac

Reputation: 55569

This has previously been filed as a bug, specifically SI-9625. Implicits values that are path-dependent and return higher-kinded types fail to resolve. Here is a simplified example using the standard library:

trait TC[F[_]]

trait Foo {
    type T[A]
    implicit val ta: TC[T]
}

object Bar {
    def use(foo: Foo) = {
        import foo._
        implicitly[TC[T]] // fails to resolve, but `implicitly[TC[T]](ta)` is fine
    }
}

Sadly, even the most obvious use of the implicit fails:

object Bar {
    def use(foo: Foo) = {
        implicit val ta: TC[foo.T] = null
        implicitly[TC[foo.T]] // nope!
    }
}

Upvotes: 1

Related Questions