Scala 可以注意到路径依赖类型之间的同一性吗?

发布于 2024-12-22 16:26:42 字数 1071 浏览 5 评论 0原文

有时在 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.BarMain.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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

不顾 2024-12-29 16:26:42

Iulian Dragos 在最近的一个问题中给出了您需要的答案。简而言之,编译器不进行流分析,因此在第一个示例中,它无法判断 foo1.Bar 和 foo2.Bar 是同一类型,因为 foo1 和 foo2 只是 Foo 类型。但在第二个示例中 foo1 被推断为单例类型 Foo.type (Foo 的子类型),因此一切按预期工作。

您可以通过将 foo2 声明为 foo1 的单例类型来使您的第一个示例正常工作:

val foo2:foo1.type = 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:

val foo2:foo1.type = foo1

See section 3.2.1 of the Scala Language Specification 2.9 for reference.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文