Scala 可以注意到路径依赖类型之间的同一性吗?
有时在 Scala 中,我发现与路径相关类型相关的类型不匹配,但我可以很容易地推断出实际上类型是一致的。这是一个简单的示例:
trait Foo { trait Bar }
object Main extends App {
val foo1 = new Foo { }
val foo2 = foo1
def turkle(x: foo1.Bar) {}
turkle(new foo2.Bar {})
}
给出:“类型不匹配;找到:java.lang.Object,需要 Main.foo2.Bar:Main.foo1.Bar”。
当然,路径 Main.foo1.Bar
和 Main.foo2.Bar
必须重合,因为我们编写了 val foo2 = foo1
。 最后一行来验证这一点
turkle((new foo2.Bar {}).asInstanceOf[foo1.Bar])
我们可以通过更改编译和运行时没有异常的
。Scala 可以自动执行这样的推理吗?如果可以,我怎样才能实现这一点?
(如果没有,是否有朝这个方向扩展类型系统的前景?)
我会注意到,有时 Scala 确实会执行这种推理。假设我将 trait Foo
更改为 object Foo
:
object Foo { trait Bar }
object Main extends App {
val foo1 = Foo
val foo2 = foo1
def turkle(x: foo1.Bar) {}
turkle(new foo2.Bar {})
}
现在一切都可以正常编译:不知何故,Scala 已经计算出 Main.foo1.Bar
和 >Main.foo2.Bar
实际上与 Foo.Bar
相同。
Sometimes in Scala I find that I get type mismatches related to path-dependent types, but I can easily reason that in fact the types coincide. Here's a simple example:
trait Foo { trait Bar }
object Main extends App {
val foo1 = new Foo { }
val foo2 = foo1
def turkle(x: foo1.Bar) {}
turkle(new foo2.Bar {})
}
which gives: "type mismatch; found : java.lang.Object with Main.foo2.Bar required: Main.foo1.Bar".
Now of course the paths Main.foo1.Bar
and Main.foo2.Bar
must coincide, since we wrote val foo2 = foo1
. We can verify this, by changing the last line to
turkle((new foo2.Bar {}).asInstanceOf[foo1.Bar])
which both compiles and runs without an exception.
Can Scala automatically perform reasoning like this? If so, how can I make this happen?
(And if not, are there any prospects for extending the type system in this direction?)
I'll note that sometimes Scala does appear to perform this sort of reasoning. Supposing I change trait Foo
to object Foo
:
object Foo { trait Bar }
object Main extends App {
val foo1 = Foo
val foo2 = foo1
def turkle(x: foo1.Bar) {}
turkle(new foo2.Bar {})
}
Now everything compiles fine: somehow Scala has worked out that both Main.foo1.Bar
and Main.foo2.Bar
are really the same as Foo.Bar
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Iulian Dragos 在最近的一个问题中给出了您需要的答案。简而言之,编译器不进行流分析,因此在第一个示例中,它无法判断 foo1.Bar 和 foo2.Bar 是同一类型,因为 foo1 和 foo2 只是 Foo 类型。但在第二个示例中 foo1 被推断为单例类型 Foo.type (Foo 的子类型),因此一切按预期工作。
您可以通过将 foo2 声明为 foo1 的单例类型来使您的第一个示例正常工作:
请参阅 Scala 语言规范 2.9 的第 3.2.1 节以供参考。
Iulian Dragos gave the answer you need in a recent question. The short version is that the compiler doesn't do flow analysis, so in your first example it can't tell that foo1.Bar and foo2.Bar are the same type since foo1 and foo2 are just of type Foo. But in the second example foo1 is inferred to be the singleton type Foo.type (a subtype of Foo), so things work as expected.
You can make your first example work by declaring foo2 as being the singleton type of foo1:
See section 3.2.1 of the Scala Language Specification 2.9 for reference.