Scala 3 match type归约失败 矩阵乘法扩展方法调用报错
问题原因
你遇到的问题核心是Scala的匹配类型(Match Type)仅支持单向推导:
- 你给匹配类型传入确定的字面量类型参数时,编译器可以正常推导出展开后的类型,比如给
V[3, Int]能得到三元组类型(Int, Int, Int),所以你声明变量指定类型为M3I时的类型校验是正常的。 - 但反过来,编译器没办法从展开后的元组类型,反向推导出它对应的匹配类型的参数。你声明的
m1虽然标注了类型是M3I,但编译器会自动把这个别名展开为原始的三元组类型,当你调用扩展方法时,编译器看到的是一个三元组值,没办法从这个三元组反推得到扩展方法需要的L、C、N三个类型参数,所以会报匹配失败的错误。
解决方法
你可以用两种常用方式解决这个问题:
方案1:用包装类保留类型参数
不要直接用元组别名,给向量和矩阵加一层简单的包装,让编译器保留住维度的类型参数:
case class Vec[I <: Int, N](value: V[I, N]) case class Mat[L <: Int, C <: Int, N](value: Mx[L, C, N]) // 声明变量的时候用包装类 val m3: Mat[3, 3, Int] = Mat( ( (1, 0, 0), (0, 1, 0), (0, 0, 1) ) ) // 扩展方法写在包装类上 extension[L <: Int, C <: Int, N] (essa: Mat[L, C, N]) @implicitNotFound(msg = "矩阵乘法要求第一个矩阵的列数等于第二个矩阵的行数,当前${C} != ${LB}") def *[LB <: Int, CB <: Int](outra: Mat[LB, CB, N])(using ev: C =:= LB) = ???
这样调用m3 * m3的时候,编译器可以直接从包装类拿到L=3、C=3、N=Int的参数,不需要反向推导匹配类型,就能正常识别扩展方法。
方案2:基于Tuple的大小直接推导
如果你不想加包装类,也可以放弃用匹配类型的参数推导,直接从元组的长度获取维度信息:
import scala.compiletime.ops.tuple.Size extension[L <: Int, Row <: Tuple, C <: Int, N] (essa: Row) (using s1: Size[Row] =:= L, s2: Size[Tuple.Elem[Row, 0]] =:= C ) def *[LB <: Int, CB <: Int, Row2 <: Tuple](outra: Row2)(using ev: C =:= LB) = ???
这种方式不需要依赖匹配类型的反向推导,编译器可以直接从元组结构拿到长度的字面量类型,也能正常完成调用。
内容的提问来源于stack exchange,提问作者Davi Pacheco
相关产品推荐
相关产品推荐

