I’m having some problems with path dependent types.
I have some types Foo with an abstract type member F. Instances such as Bar will provide the concrete type.
Then there is a type class Baz. I have instances of the type class for each concrete type of Foo#F (but not for Foo itself).
Here is an example:
sealed trait Foo {
type F
}
object Bar extends Foo {
type F = Array[Byte]
}
trait Baz[B] {
def b(b: B): String
}
object Baz {
implicit val bazByteArray: Baz[Array[Byte]] = (b: Array[Byte]) => new String(b)
}
I can't get this to compile:
def f(a: Foo): Baz[a.F] = {
val baz = a match {
case bar@Bar => g(bar)
}
baz
} // Expression of type Baz[(a.type with Bar.type)#F] doesn't conform to Baz[a.F]
val x2: Foo = Bar
val y2: Baz[x2.F] = f(x2) // Expression of type Baz[Foo#F] doesn't conform to expected type Baz[x2.F]
This does compile:
def g(a: Foo)(implicit baz: Baz[a.F]): Baz[a.F] = {
baz
}
val x1: Bar.type = Bar
val y1: Baz[x1.F] = f(x1)
Why does g compile but not f? Aren't the types the same?
How can I get f to compile? Is there some sort of evidence I need to add?