I am trying to create an implementation of a trait that uses a match type, where the right-hand-side of that match type is known in advance. However, I can't seem to get the compiler to accept my "proof" of this. This is pretty new to me, so sorry if this is really obvious. Can someone help me understand if/how I can achieve what I want?
Here's some minimal code (Scastie) to illustrate what I'm doing:
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()
}
// here we prove that Boxer.Box[T] is a 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))
But this fails with:
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()
Scala doesn't automatically apply proofs in the way you're looking for. But you're right that you do have a proof. In fact, your proof constitutes a callable object: the type
=:=[From, To]defines a method calledapply:Now, you have a value of type
Boxer.Box[T] =:= NumberBox, which means thatapplywould convert aBoxer.Box[T]to aNumberBox. You want the opposite: to convert aNumberBoxinto aBoxer.Box[T]. So we need toflipyour proof around and thenapplyit.In your specific use case, consider
We give the proof argument a name,
eq, and then we apply its symmetric proof (thatNumberBox =:= Boxer.Box[T]) to ourNumberBoxto convert it to the desired type.You could also just take a proof that
NumberBox =:= Boxer.Box[T]directly and get rid of theflip, if desired.