如何证明Scala匹配类型可解析为特定具体类型?
Scala匹配类型(Match Type)的类型证明问题
我正尝试实现一个使用match type的trait,该匹配类型的右侧类型预先已知,但无法让编译器接受我的类型证明。这对我来说比较陌生,若问题浅显还请见谅。能否有人帮我理解如何实现需求?
最小复现代码
class NumberBox {} class LongBox {} trait Boxer[T] { def box(): Boxer.Box[T] } object Boxer { type Box[T] = T match case Long => LongBox case _ => NumberBox } case class Val[T](v: T) extends Boxer[T] { def box(): Boxer.Box[T] = v match case _: Long => new LongBox() case _ => new NumberBox() } // 此处我们试图证明Boxer.Box[T]是NumberBox case class NoLongs[T](v: Boxer[T])(using Boxer.Box[T] =:= NumberBox) extends Boxer[T] { override def box(): Boxer.Box[T] = new NumberBox() } NoLongs(Val(1))
编译错误信息
Found: NumberBox Required: Boxer.Box[T] Note: a match type could not be fully reduced: trying to reduce Boxer.Box[T] failed since selector T does not match case Long => LongBox and cannot be shown to be disjoint from it either. Therefore, reduction cannot advance to the remaining case case _ => NumberBox override def box(): Boxer.Box[T] = new NumberBox()
解决方案
问题出在编译器无法自动利用Boxer.Box[T] =:= NumberBox这个类型等式证据完成类型转换,必须显式调用该证据来实现转换:
修改NoLongs类的实现:
case class NoLongs[T](v: Boxer[T])(using ev: Boxer.Box[T] =:= NumberBox) extends Boxer[T] { override def box(): Boxer.Box[T] = ev(new NumberBox()) }
原理说明
=:=本质是一个函数式的类型证据,它的apply方法可以将右侧类型的实例转换为左侧类型的实例。虽然编译器知道Boxer.Box[T]和NumberBox等价,但不会自动执行转换,必须显式调用这个证据来让编译器确认类型兼容性。
当调用NoLongs(Val(1))时,编译器会推导出T为Int,此时Boxer.Box[Int]会被归约为NumberBox,对应的类型等式证据会被自动合成,无需手动传入。
内容的提问来源于stack exchange,提问作者fehrvuerh93
相关产品推荐
相关产品推荐

