Is there a way to get the compiler to somehow consider type aliases when looking for implicit evidence?
Here is an example of problem I am trying to solve:
// Third party library
class Foo[T, P]
class FooOps[FTP, T] {
def apply[F[_, _], P](t: T)(implicit ev: F[T, P] =:= FTP): FTP = ???
}
type StringFoo = Foo[String, Boolean]
object StringFoo extends FooOps[StringFoo, String]
StringFoo("hello")
// Attempt to wrap the third party type but have the same ops
class WrappedFoo[FTP](val foo: FTP)
object WrappedFoo {
type F[T, P] = WrappedFoo[Foo[T, P]]
}
type WrappedStringFoo = WrappedFoo[StringFoo]
object WrappedStringFoo extends FooOps[WrappedStringFoo, String]
WrappedStringFoo("hello") // Cannot prove that F[String, P] =:= WrappedStringFoo
WrappedStringFoo[WrappedFoo.F, Boolean]("hello”) // This works
I don't quite understand how the compiler infers the types in:
StringFoo("hello")
Does it somehow use the available implicits to choose a value for F[_, _]
? I always thought that it had to work out the types first.
However it works for StringFoo
it doesn't work for WrappedStringFoo
. Likely since the number of type parameters is different.
How can I get:
WrappedStringFoo("hello")
to compile without specifying the types explicitly?
Try to add necessary implicit to scope:
import scala.language.higherKinds
class Foo[T, P]
class FooOps[FTP, T] {
def apply[F[_, _], P](t: T)(implicit ev: F[T, P] =:= FTP): FTP = ???
}
type StringFoo = Foo[String, Boolean]
object StringFoo extends FooOps[StringFoo, String]
class WrappedFoo[FTP](val foo: FTP)
object WrappedFoo {
type F[T, P] = WrappedFoo[Foo[T, P]]
//implicit val ev0: WrappedFoo.F[String, Boolean] =:= WrappedStringFoo = ???
implicit val ev0: WrappedFoo.F[String, Boolean] =:= WrappedStringFoo =
null.asInstanceOf[WrappedFoo.F[String, Boolean] =:= WrappedStringFoo]
}
type WrappedStringFoo = WrappedFoo[StringFoo]
object WrappedStringFoo extends FooOps[WrappedStringFoo, String]
WrappedStringFoo("hello")
When you do StringFoo("hello")
compiler solves equation F[String, P] = Foo[String, Boolean]
and it's smart enough to deduce P = Boolean
, F = Foo
. But when you do WrappedStringFoo("hello")
compiler has to solve equation F[String, P] = WrappedFoo[Foo[String, Boolean]]
and algorithms it uses are not smart enough to deduce P = Boolean
, F = ({ type λ[A, B] = WrappedFoo[Foo[A, B]] })#λ
i.e. WrappedFoo.F
(and possibly such equations can't be solved in general if they are advanced enough). So you should provide a hint. Either specifying type parameters explicitly or providing necessary implicit evidence.
Resolving implicits and type inference make impact on each other. You can read section 4.4.3 of Eugene Burmako's thesis.