Scala: a generic multiplication function of Numerics of various types

I am trying to write a general weighted average function. I want to relax the requirements for values ​​and weights of the same type. those. I want to support word sequences: (value:Float,weight:Int) and (value:Int,weight:Float) arguments, and not just: (value:Int,weight:Int)

To do this, I first need to implement a function that takes two common numerical values ​​and returns their product.

 def times[A: Numeric, B: Numeric](x: B, y: A): (A, B) : ??? = {...} 

Writing down the signature and thinking about the return type, I realized that I needed to define some kind of hierarchy for Numerics to determine the return type. those. x:Float*y:Int=z:Float , x:Float*y:Double=z:Double .

Now the number class defines operations plus , times , etc. only for arguments of the same type. I think I will need to implement a type:

 class NumericConverter[Numeirc[A],Numeric[B]]{ type BiggerType=??? } 

so that I can write my time function as:

 def times[A: Numeric, B: Numeric](x: B, y: A): (A, B) : NumericConverter[Numeirc[A],Numeric[B]].BiggerType= {...} 

and convert the "smaller type" to "large" and pass it to times() .

Am I on the right track? How do I "implement" BiggerType ?

clear i can't do something like:

 type myType = if(...) Int else Float 

as it is being evaluated dynamically, therefore it does not work.

I understand that I could do this. Using Scalaz, etc., but this is an academic exercise, and I want to understand how to write a function that statically returns a type based on argument types .

Feel free to let me know if there is an even easier way to do this.

Update

that's what i came up with.

 abstract class NumericsConvert[A: Numeric,B: Numeric]{ def AisBiggerThanB: Boolean def timesA=new PartialFunction[(A,B), A] { override def isDefinedAt(x: (A, B)): Boolean = AisBiggerThanB override def apply(x: (A, B)): A = implicitly[Numeric[A]].times(x._1, x._2.asInstanceOf[A]) } def timesB=new PartialFunction[(A,B), B] { override def isDefinedAt(x: (A, B)): Boolean = !AisBiggerThanB override def apply(x: (A, B)): B = implicitly[Numeric[B]].times(x._1.asInstanceOf[B], x._2) } def times: PartialFunction[(A, B), Any] = timesA orElse timesB } def times[A: Numeric, B: Numeric](x: B, y: A)= implicitly[NumericsConvert[A,B]].times(x,y) 

which is stupid since I have to create implications for

 IntDouble extends NumericsConvert[Int,Double] 

and

 DoubleInt extends NumericsConvert[Double,Int] 

not to mention that the return type of times now Any , but independently, I get errors for my time functions. I thought I would add it here if this helps in solving the problem. so the side question: how can I pass context-related types of one class / function to another, as I try to do at times .

+6
generics scala implicit numeric
source share
1 answer

I think you make it harder than it should be.

You need “evidence” that both parameters are Numeric . Given that evidence supports this work. Scala will use a numerical extension to make the result more general of the two types obtained.

 def mult[T](a: T, b: T)(implicit ev:Numeric[T]): T = ev.times(a,b) 

If you want to get a little involved, you can pull in the necessary implications. Then it's a little easier to read and understand.

 def mult[T: Numeric](a: T, b: T): T = { import Numeric.Implicits._ a * b } 

Evidence:

 mult(2.3f , 7) //res0: Float = 16.1 mult(8, 2.1) //res1: Double = 16.8 mult(3, 2) //res2: Int = 6 

More on generic types and numerical expansion, this question and its answer is worth exploring.

+7
source share

All Articles