存在类型如何与路径依赖类型重叠?

How do existential types overlap with path-dependent types?

启动 Scala 3 存在类型 dropped 并且其中一个原因是

Existential types largely overlap with path-dependent types, so the gain of having them is relatively minor.

鉴于“大部分”,所以并非总是如此,我想知道是否可以提供一个具体示例来演示如何将存在类型重写为路径相关类型,以及无法进行此类替换的示例?

假设 T 是我们要通过存在量词绑定的类型,而 F[T] 是依赖于 T 的某种类型,因此

type A = F[T] forSome { type T }

是我们的存在类型。

提供类型 A 的实例意味着:

  • 存在某种类型 t 可以被 T
  • 绑定
  • 存在 F[t]
  • 类型的值

但我们也可以将两个组件放入一个类型中,并使 T 成为路径相关的类型成员:

type B = { type T; val value: F[T] }

B 类型的实例由相同的数据描述:

  • 某些类型 t 可以由名称 T 绑定。
  • F[t]
  • 类型的值

AB 的值携带大致相同的信息,主要区别在于我们如何访问我们正在量化的类型 T。在 b: B 的情况下,我们可以将其作为路径相关类型 p.T 获取,而对于 a: A,我们可以在模式匹配中使用类型变量。

下面是一个示例,演示如何在存在量化类型和路径相关类型之间进行映射:

def example[F[_]]: Unit = {
  type A = F[T] forSome { type T }
  type B = { type T; val value: F[T] }
  def ex2pd(a: A): B = a match {
    case v: F[t] => new { type T = t; val value = v }
  }
  def pd2ex(b: B): A = b.value
}

(在 2.13 上编译)

我猜“很大程度上”在那里,因为与 Scala 3 / Dotty 不同,以前的 Scala 版本没有任何严格形式化的基础,所以这句话的作者可能只是不想引用印象2.13 中的每个存在类型都可以由路径依赖类型精确表示,因为这样的声明无论如何都不够严格。