Scala路径依赖类型用作函数codomain时无法为函数加别名的原因是什么?
问题核心原因解析
你提到的P#Repr的正式名称是类型投影(type projection),属于Scala 2特有的语法,确实不在DOT演算的定义范围内,Scala 3对它的支持做了严格限制,仅在安全场景下允许使用。
报错中(some other)的来源
你遇到的类型不匹配错误根源是存在量词绑定的通配符路径丢失:
- 你定义的
Consequent = Proposition[_ <: OUT]里的_是存在量化的类型参数,每一次出现的_ <: OUT都会被编译器分配独立的匿名类型变量(也就是错误信息里的_$1) P <: Consequent里的Consequent绑定了第一个匿名_$1,而你取P#Repr的时候,编译器无法将这个类型投影和P内部绑定的那个存在类型参数关联起来,会把P#Repr解析为另一个独立的匿名_$1,所以就出现了「找到某一个_$1,要求另一个_$1」的错误,错误里的(some other)就是指代这两个不属于同一个绑定上下文的匿名类型变量。
这个不是编译器bug,是Scala 2类型投影设计本身的缺陷:类型投影默认不携带路径信息,当作用在含有存在类型的上层绑定时,编译器无法溯源到最初的存在量词绑定,就会产生独立的匿名类型实例,触发类型冲突。
Scala 3的支持情况
Scala 3默认已经禁用了通用的类型投影语法,仅保留了合法类型投影(legal type projection):只有当被投影的类型参数是final、或者投影的类型是和外部路径无关的固定类型时,才允许使用#语法。
你的代码在Scala 3中会直接编译失败,提示Projection P#Repr is not allowed, since it references a type parameter P that is not a class type,不会再出现之前的匿名类型冲突错误。如果你要实现类似的功能,在Scala 3中需要改用路径依赖类型,绑定具体的实例路径,而不是用类型投影。
补充说明
针对你更新里的两个疑问:
- 类型投影是Scala 2为了访问抽象类型成员提供的语法,和路径依赖类型
p.Repr的区别是:路径依赖类型绑定了具体的实例p,而类型投影仅绑定了类型P,不携带实例信息。 - 因为DOT演算的核心是路径依赖类型,没有为无路径的类型投影设计对应的规则,所以Scala 3逐步废弃了通用类型投影的用法,推荐全部改用带实例路径的类型选择来实现相同功能。
内容的提问来源于stack exchange,提问作者tribbloid
相关产品推荐
相关产品推荐

