简体   繁体   English

路径依赖类型(在类型和内部类上)

[英]Path dependent types (on types and on inner classes)

While experimenting with path dependent types, I experienced some unexpected results:在试验路径依赖类型时,我遇到了一些意想不到的结果:

object Funny1 {
  class X {
    type Y = String
    val y: Y = "y"
  }

  val x1 = new X
  val x2 = new X

  def foo(x: X)(y: x.Y): Unit = ()
  def foo_diff(y1: x1.Y)(y2: x2.Y): Unit = () // 1.3
  def foo_gen(y1: X#Y)(y2: X#Y) : Unit = ()

  foo(x1)(x1.y)
  foo(x1)(x2.y) // <-- 1.1 would expect this to fail

  foo_diff(x1.y)(x2.y)
  foo_diff(x2.y)(x2.y) // <-- 1.2 would expect this to fail

  foo_gen(x1.y)(x2.y)
  foo_gen(x2.y)(x2.y)
}


object Funny2 {
  class X {
    class Y {
    }
  }

  val x1 = new X
  val x2 = new X

  val x1y = new x1.Y
  val x2y = new x2.Y

  def foo(x: X)(y: x.Y): Unit = ()
  def foo_diff(y1: x1.Y)(y2: x2.Y): Unit = ()
  def foo_gen(y1: X#Y)(y2: X#Y) : Unit = ()

  foo(x1)(x1y)
  // foo(x1)(x2y) // does not compile

  foo_diff(x1y)(x2y)
  // foo_diff(x2y)(x2y) // does not compile

  foo_gen(x1y)(x2y)
  foo_gen(x2y)(x2y)
}

object Funny3 {
  trait X {
    type Y
    def y: Y
  }

  val x1 = new X {
    override type Y = String

    override def y: String = "y"
  }
  val x2 = new X {
    override type Y = Int

    override def y: Int = 3
  }

  def foo(x: X)(y: x.Y): Unit = ()
  def foo_diff(y1: x1.Y)(y2: x2.Y): Unit = ()
  def foo_gen(y1: X#Y)(y2: X#Y) : Unit = ()

  foo(x1)(x1.y)
  // foo(x1)(x2.y)    // 3.1 fails as expected

  foo_diff(x1.y)(x2.y)
  // foo_diff(x2.y)(x2.y)  // 3.2 fails as expected

  foo_gen(x1.y)(x2.y)
  foo_gen(x2.y)(x2.y)
}



object Funny3b {
  trait X {
    type Y
    def y: Y
  }

  val x1 = new X {
    override type Y = String

    override def y: String = "y"
  }
  val x2 = new X {
    override type Y = String

    override def y: String = "y2"
  }

  def foo(x: X)(y: x.Y): Unit = ()
  def foo_diff(y1: x1.Y)(y2: x2.Y): Unit = ()
  def foo_gen(y1: X#Y)(y2: X#Y) : Unit = ()

  foo(x1)(x1.y)
  foo(x1)(x2.y)    // 3b.1 does not fail

  foo_diff(x1.y)(x2.y)
  foo_diff(x2.y)(x2.y)  // 3b.2 does not fail

  foo_gen(x1.y)(x2.y)
  foo_gen(x2.y)(x2.y)
}

Especially, I am interested in the answers to the questions:特别是,我对以下问题的答案很感兴趣:

  • Why do the line marked 1.1 and 1.2) compile?为什么标记为 1.1 和 1.2) 的行会编译?
  • Why is no reference to x as first parameter required in 1.3 foo_diff ?为什么在 1.3 foo_diff不需要将x作为第一个参数的foo_diff
  • Why do the lines 3.1 and 3.2 not compile, but 3b.1 and 3b.2 compile?为什么 3.1 和 3.2 行没有编译,但 3b.1 和 3b.2 编译? Especially as the path dependency seems to be "lost" in 3b, if underlying types can be resolved to be identical (here: String).特别是当路径依赖似乎在 3b 中“丢失”时,如果底层类型可以解析为相同(此处:字符串)。

Thanks, Martin谢谢,马丁

I think the fundamental misunderstanding that underlies all of your question is that you assume that a construction:我认为构成你所有问题的根本误解是你假设一个结构:

trait / class ClassName {
  type T = something
} 

creates a dependent type.创建一个依赖类型。 It doesn't.它没有。 If you open the subsection 3.5.1 Equivalence of the section 3.5 "Relations between types" of the spec, you may see that:如果您打开规范的第 3.5 节“类型之间的关系”的第3.5.1等效性,您可能会看到:

  • If t is defined by a type alias type t = T , then t is equivalent to T .如果t由类型别名 type t = T ,则t等价于T

That's why in your first example for example, compiler sees x1.Y and x2.Y and X#Y as just String .这就是为什么在您的第一个示例中,编译器将x1.Yx2.YX#Y视为String If you substitute all that with just String there are no questions left on why that code compiles.如果你只用String代替所有这些,那么关于为什么该代码编译就没有问题了。

Similarly your 3rd example just define some aliases.同样,您的第三个示例只是定义了一些别名。 If you substitute those aliases with their definitions, it again becomes quite clear why that code compiles and fails.如果你用它们的定义替换这些别名,那么代码编译和失败的原因就变得很清楚了。

Your second example uses a different construct您的第二个示例使用不同的构造

trait / class ClassName {
  trait / class InnerName
} 

This is the construct that creates a path-dependent type and thus the code you expect to not compile actually fails.这是创建依赖于路径的类型的构造,因此您期望不编译的代码实际上失败了。 According to my understanding this is the only of your examples that really involves dependent types.根据我的理解,这是您唯一真正涉及依赖类型的示例。

Also if you open Tour of Scala articles Abstract Type Members and Inner Classes that describe the first and the second construction, you might notice that only the latter (but not the former!) mentions the "path-dependent types".此外,如果您打开描述第一个和第二个构造的 Scala 文章抽象类型成员内部类,您可能会注意到只有后者(而不是前者!)提到了“路径依赖类型”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM