【问题标题】:Path dependent types (on types and on inner classes)路径依赖类型(在类型和内部类上)
【发布时间】:2019-06-06 15:19:15
【问题描述】:

在试验路径依赖类型时,我遇到了一些意想不到的结果:

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)
}

特别是,我对问题的答案很感兴趣:

  • 为什么标记为 1.1 和 1.2) 的行会编译?
  • 为什么在 1.3 foo_diff 中没有引用 x 作为第一个参数?
  • 为什么行 3.1 和 3.2 不编译,但 3b.1 和 3b.2 编译?尤其是路径依赖似乎在 3b 中“丢失”了,如果可以将底层类型解析为相同(这里:字符串)。

谢谢,马丁

【问题讨论】:

    标签: scala types path-dependent-type


    【解决方案1】:

    我认为构成你所有问题的根本误解是你假设一个结构:

    trait / class ClassName {
      type T = something
    } 
    

    创建一个依赖类型。它没有。如果您打开规范第 3.5 节“类型之间的关系”的 3.5.1 Equivalence 小节,您可能会看到:

    • 如果t 由类型别名类型t = T 定义,则t 等效于T

    这就是为什么在您的第一个示例中,例如,编译器将x1.Yx2.YX#Y 视为String。如果您只用 String 替换所有这些,那么对于该代码编译的原因就没有问题了。

    同样,您的第三个示例只是定义了一些别名。如果您用它们的定义替换这些别名,那么代码编译和失败的原因就很清楚了。

    您的第二个示例使用了不同的构造

    trait / class ClassName {
      trait / class InnerName
    } 
    

    这是创建路径相关类型的构造,因此您希望不编译的代码实际上会失败。据我了解,这是您的示例中唯一真正涉及依赖类型的示例。

    此外,如果您打开 Tour of Scala 文章 Abstract Type MembersInner Classes 描述了第一种和第二种构造,您可能会注意到只有后者(但不是前者!)提到“路径依赖类型”。

    【讨论】:

      猜你喜欢
      • 2019-06-03
      • 1970-01-01
      • 2013-04-17
      • 2016-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-27
      相关资源
      最近更新 更多