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

问题描述

启动 Scala 3 存在类型是 dropped 并且原因之一被陈述为

存在类型与路径依赖类型在很大程度上重叠,所以 拥有它们的收益相对较小。

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

解决方法

假设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 中的存在类型可以由路径依赖类型精确表示,因为这样的声明无论如何都不能严格。