Scala Generics and Numerical Implits

I need to pass two functions as parameters to a scala function. Then this function should evaluate them and get from them the number in which it will work. This number can be either Int, Double, or any other number type. I would like the function to work no matter what it works with.

The following example explains the problem.

import Numeric.Implicits._ class Arithmetic[T : Numeric](val A: Connector[T], val B: Connector[T]) { val sum = new Connector({ A.value + B.value }) } class Constant[T](var x: T) { val value = new Connector({ x }) } class Connector[T](f: => T) { def value: T = f override def toString = value.toString() } object Main extends App{ val n1 = new Constant(1) // works val n5 = new Constant(5) val a = new Arithmetic( n1.value, n5.value ) println(a.sum) // no works val n55 = new Constant(5.5) val b = new Arithmetic( n1.value, n55.value ) println(b.sum) } 

I also tried

 class Arithmetic[T,R : Numeric](val A: Connector[T], val B: Connector[R]) { 

and a few other combinations, but I ended up with

 error: could not find implicit value for parameter num: scala.math.Numeric[Any] val sum = new Connector({ A.value + B.value }) 
+7
source share
1 answer

The error message you see is due to the fact that Numeric[T].plus can only be used to add two values ​​of the same type T Your code is written under the assumption that the numerical extension happens automatically - which will not happen in this case, since the compiler does not know anything about types, except that there is an instance of Numeric[T] .

If you need sum be a stable value, you will need to provide the necessary type information in the constructor, for example:

 class Arithmetic[A : Numeric, R <% A, S <% A](val a: Connector[R], b: Connector[S]) { val sum = new Connector[A]((a.value:A) + (b.value:A)) } 

This requires that the types R and S be convertible to some type A , for which the value Numeric[A] is known. When creating an instance, you always need to provide all type parameters, since they cannot be inferred.

If you don't need sum be stable, you can change your class to this:

 class Arithmetic[A,B](val a: Connector[A], val b: Connector[B]) { // if A and B are the same types def sum(implicit e: B =:= A, n: Numeric[A]): Connector[A] = new Connector(n.plus(a.value, b.value)) // else widen to C def wideSum[C](implicit f: A => C, g: B => C, n: Numeric[C]) = new Connector(n.plus(a.value, b.value)) } val a = new Connector(1) val b = new Connector(2) val c = new Connector(3.0) val d = (new Arithmetic(a,b)).sum // val e = (new Arithmetic(b,c)).sum // <-- does not compile val e = (new Arithmetic(b,c)).wideSum[Double] 

When expanding, you still have to provide type information.

+4
source

All Articles