Context boundaries and pattern matching in scala

I am experimenting with context bounds in scala and I can't find a way to do one of these two typecheck functions:

abstract class Expr
case class Val[T: Numeric](v: T) extends Expr
case object Other extends Expr

val e1 = Val(1)
val e2 = Val(2)

def addExp1(e1: Expr, e2: Expr): Expr = (e1, e2) match {
  case (Val(v1), Val(v2)) => Val(v1+v2)
  case _ => Other
}

def addExp2[T: Numeric](e1: Expr, e2: Expr): Expr = (e1, e2) match {
  case (Val(v1: T), Val(v2: T)) => Val(v1+v2)
  case _ => Other
}

      

In the case of addExp1, I can understand that the compiler has no information at the point of the function definition to know that the Val arguments are numeric and therefore have a + method. It just matches Any as type v1.

In the case of addExp2, how can I force the binding in the template? Type "erased" ... T annotation removed by erasure ...

What I would have dreamed of having is a single point to put a border, ideally in the definition of the Val class.

+3


source to share


2 answers


The problem is that when matching templates, the two instances Val

may have different type parameters, such as Val[T1]

and Val[T2]

.



You can fix this as suggested by @rjsvaljean and add import Numeric.Implicits._

to use nice operator notation.

+3


source


One way to avoid losing the parameterized type Val is to have Expr also a type parameter.

abstract class Expr[T]
case class Val[T: Numeric](v: T) extends Expr[T]
case object Other extends Expr[Nothing]

val e1 = Val(1)
val e2 = Val(2)



def addExp2[T: Numeric](e1: Expr[T], e2: Expr[T]): Expr[_ <: T] = (e1, e2) match {
  case (Val(v1), Val(v2)) => Val(implicitly[Numeric[T]].plus(v1, v2))
  case _ => Other
}


addExp2[Int](e1, e2)

      



This compiles with no warnings.

Now we need to specify the default type Nothing

for the type parameter Expr :).

+3


source







All Articles