[英]How to use path-dependent types with type classes in Scala
I'm having some problems with path dependent types. 我在路径依赖类型方面遇到了一些问题。
I have some types Foo
with an abstract type member F
. 我有一些类型
Foo
与抽象类型成员F
Instances such as Bar
will provide the concrete type. Bar
等实例将提供具体类型。
Then there is a type class Baz
. 然后有一个类型
Baz
。 I have instances of the type class for each concrete type of Foo#F
(but not for Foo
itself). 我为每个具体类型的
Foo#F
都有类型类的实例(但不适用于Foo
本身)。
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
? 为什么
g
编译而不是f
? Aren't the types the same? 这些类型不一样吗?
How can I get f
to compile? 如何编译
f
? Is there some sort of evidence I need to add? 我需要添加某种证据吗?
Seems somewhat similar to this question . 似乎有点类似于这个问题 。 Here is a way to make it compile:
这是一种使其编译的方法:
sealed trait Foo {
type F
def asSingleton: FooSingleton[F]
}
trait FooSingleton[X] extends Foo {
type F = X
def asSingleton: FooSingleton[X] = this
}
object Bar extends FooSingleton[Array[Byte]]
trait Baz[B] {
def b(b: B): String
}
object Baz {
implicit val bazByteArray: Baz[Array[Byte]] =
(b: Array[Byte]) => new String(b)
}
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)
def f[T](a: Foo { type F = T } ): Baz[T] = {
(a.asSingleton: FooSingleton[T]) match {
case bar @ Bar => g(bar)
}
}
val x2: Foo = Bar
val y2: Baz[x2.F] = f(x2)
Your g
compiles, because the path-dependent argument baz
of type Baz[aF]
comes from the outside , a concrete implicit instance is inserted by the compiler, and the actual value a
isn't used anywhere inside g
. 你的
g
编译,因为Baz[aF]
类型的路径相关参数baz
来自外部 ,编译器插入一个具体的隐式实例,而实际值a
不在g
内的任何地方使用。
Your f
does not compile, because the B[aF]
appears only in the return type, and it cannot be made more concrete before an actual argument a
is passed to f
. 你的
f
不能编译,因为B[aF]
只出现在返回类型中,并且在将实际参数a
传递给f
之前不能使它更具体。
In a sense, the f
breaks the path between the argument a
and the returned value, because it makes the following "discontinuous jumps": 从某种意义上说,
f
打破了参数a
和返回值之间的路径,因为它会产生以下“不连续跳转”:
a: Foo
a: Foo
开始 a
to the Bar
singleton (by pattern-matching) a
跳转到Bar
singleton(通过模式匹配) g
to get from the concrete Bar
singleton to the concrete Baz[Array[Byte]]
g
从具体的Bar
单例到混凝土Baz[Array[Byte]]
Baz[Array[Byte]]
, which seems no longer connected to Baz[aF]
. Baz[Array[Byte]]
,它似乎不再连接到Baz[aF]
。 This path can be repaired by proving that the discontinuous "jump" is indeed just an identity path that stays in the same spot all the time, so it really doesn't move anywhere, so that aF
and the inferred type are the same, namely T
. 这条路径可以通过证明不连续的“跳跃”确实只是一直保持在同一点的标识路径来修复,所以它实际上不会移动到任何地方,因此
aF
和推断类型是相同的,即T
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.