You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 12:06:03