Scala 3自定义Either重关联match type无法规约问题咨询
问题原因
Scala 3 匹配类型(Match Type)的规约有一个核心规则:只有当编译器能明确证明当前选择器与前序case完全不兼容时,才会进入后续case的判断,否则会直接终止规约并报错。
为什么Rebalance会失败
你定义的Rebalance前两个case的模式存在天然重叠:
case Either[Either[a, b], c] => ... // 匹配左参数为Either的情况 case Either[a, Either[b, c]] => ... // 匹配右参数为Either的情况
对于类似Either[Either[Int, String], Either[Boolean, Long]]的类型,它同时符合两个case的模式,编译器无法证明两个case的排他性。当规约到Either[Int, Either[String, Either[Boolean, Long]]]时,编译器不会主动推导「Int不可能是Either[_, _]的子类型」这个否定事实(避免类型别名、隐式扩展等边界场景导致判断错误),因此无法确定它完全不匹配第一个case,也就不会进入第二个case继续递归。
为什么RebalancePair能正常工作
RebalancePair是对二元组做结构匹配:
case (Either[a, b], c) => ... // 仅匹配元组第一个元素为Either的情况 case (a, Either[b, c]) => ... // 第一个元素不匹配时,才会走到该分支
两个case的匹配逻辑是天然排他的:如果第一个case不匹配,就说明元组的第一个元素绝对不是Either,不存在同时匹配两个case的可能,编译器可以安全地进入后续case的判断。
修复直接实现Rebalance的方案
你只需要给第一个case的左参数加上Either[_, _]的上界约束,明确告诉编译器只有当左参数是Either的子类型时才匹配该case,编译器就可以正常做排他性判断:
type Rebalance[A] = A match case Either[L <: Either[_, _], R] => Rebalance[Either[L#Left, Either[L#Right, R]]] case Either[L, R <: Either[_, _]] => Either[L, Rebalance[R]] case Either[L, R] => Either[L, R] // 测试用例 type Balanced = Int Either (String Either (Boolean Either Long)) summon[Rebalance[(Int Either String) Either (Boolean Either Long)] =:= Balanced] // 编译通过
你也可以直接基于这个Rebalance实现对应的依赖类型函数:
def rebalance[A](e: A): Rebalance[A] = e match case e @ Left(Left(a)) => rebalance(Left(a).asInstanceOf[Either[Any, Any]]) case e @ Left(Right(b)) => Right(rebalance(Left(b).asInstanceOf[Either[Any, Any]])) case e @ Right(Left(b)) => Right(rebalance(Left(b).asInstanceOf[Either[Any, Any]])) case e @ Right(Right(c)) => Right(rebalance(Right(c).asInstanceOf[Either[Any, Any]])) case e: Either[_, _] => e
内容的提问来源于stack exchange,提问作者Sergey Kolbasov
相关产品推荐
相关产品推荐

