Scala 3:处理依赖路径的类型



考虑以下片段:

object Test extends App {
class X {
class Y
}
class Z(val x: X) {
val y: x.Y = new x.Y
}
val x: X = new X
val z: Z = new Z(x)
val y: x.Y = z.y
println(y)
}

这段代码无法编译,抱怨不兼容的路径依赖类型:

[error] 12 |  val y: x.Y = z.y
[error]    |               ^^^
[error]    |               Found:    (Test.z.y : Test.z.x.Y)
[error]    |               Required: Test.x².Y
[error]    |
[error]    |               where:    x  is a value in class Z
[error]    |                         x² is a value in object Test
[error]    |

有没有一种方法可以温和地提醒编译器z.x被分配给上面一行的x

即使if (z.x == x) { val y: x.Y = z.y }也不能解决这个问题,即使应该从控制流中推断出路径等价性。

背景:Scala3宏API大量使用PDT,这造成了巨大的痛苦——所有这些痛苦都来自于编译器无法推断任何东西,以及缺乏明确控制推断的语法结构。

这是路径相关类型的正确行为(顺便说一句,在Scala 2中也是如此(。

你对满意吗

val y: z.x.Y = z.y // compiles

z.x等于x,但这并不意味着类型z.x.Yx.Y

类似地,

class A {
type T
}
val a = new A
val a1 = a
//implicitly[a.T =:= a1.T] // doesn't compile

a等于a1,但这并不意味着类型a.Ta1.T

这是Scala 2规范,用于等效路径相关类型:https://scala-lang.org/files/archive/spec/2.13/03-types.html#equivalence.在我们的例子中,前缀有不同的单例类型:

implicitly[z.x.type =:= x.type] // doesn't compile
  • 如果路径p具有单例类型q.type,则p.type ≡ q.type
  • 如果O由对象定义,并且p是路径仅由包或对象选择器组成,并以O结尾,则CCD_ 18

您可以修复编译:

class A {
type T
}
val a = new A
val a1: a.type = a
implicitly[a.T =:= a1.T] // compiles

class X {
class Y
}
class Z(val x: X) {
type V = x.Y // added
val y: V = new x.Y
}
val x: X = new X
val z: Z = new Z(x)
val y: z.V = z.y // compiles

另请参阅:

在scala(2.12.x(的最新版本中,路径相关类型的实现是否不完整?

无法证明与路径相关类型的等价性

隐式调用的力相关类型解析

如何帮助Scala3编译器推断依赖于路径的类型?

如何使用shapeless 为具有依赖类型的typeclass创建实例

如果您使用REPL,您将看到编译器推断的类型(删除注释中建议的@LuisMiguelMejíaSuárez的显式类型注释(:

scala> class X {
|   class Y
| }
class X
scala> class Z(val x: X) {
|   val y: x.Y = new x.Y
| }
class Z
scala> val x = new X
val x: X = X@6f76c2cc
scala> val z = new Z(x)
val z: Z = Z@7e62cfa3
scala> val y = z.y
val y: z.x.Y = X$Y@52bd9a27  // notice z.x, not x

最新更新