Scala:通用函数乘以不同类型的数字 [英] Scala: generic function multiplying Numerics of different types
问题描述
我想放宽对相同类型的值和权重的要求。即我想支持如下的序列:
(value:Float,weight:Int)
和(value:Int,weight:Float) code>参数,而不仅仅是:(value:Int,weight:Int)
,我首先需要实现一个函数,它采用两个通用数值并返回它们的产品。 (B,y:A):(A,B)(b)数字,B:数字:??? = {...}
编写签名并思考返回类型,让我意识到我需要为Numerics定义某种分层结构来确定返回类型。即 x:Float * y:Int = z:Float
, x:Float * y:Double = z:Double
。
$ b 现在,Numeric类定义了操作加上
,次
等仅适用于相同类型的参数。我想我需要实现一个类型:
类NumericConverter [Numeirc [A],Numeric [B]] {
类型BiggerType = ???
}
这样我可以将我的时间函数写成:
def times [A:数字,B:数字](x:B,y:A):(A,B):
NumericConverter [Numeirc [A],Numeric [B]]。BiggerType = {...}
较小的类型为较大的一个,并将它提供给 times()
。
正确的轨道?我该如何实施 BiggerType
?
显然我不能这样做:
type myType = if(...)Int else Float
,因为它是动态评估的,所以它不会工作。
我明白我可以做到这一点使用Scalaz等,但这是一个学术练习,我想了解如何编写一个基于参数类型静态返回类型的函数。
请随时告诉我是否有更简单的方法。
更新:
这就是我想出来的。
abstract class NumericsConvert [A:Numeric,B:Numeric] {
def AisBiggerThanB:Boolean
def timesA = new PartialFunction [(A,B),A ] {
覆盖def isDefinedAt(x:(A,B)):Boolean = AisBiggerThanB
覆盖def apply(x:(A,B)):A =隐式地[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:数字](x:B,y:A)=隐式地[NumericsConvert [A,B]]。times(x,y)
这很愚蠢,因为我将不得不为两者创建含义
IntDouble扩展NumericsConvert [Int,Double]
和
DoubleInt扩展NumericsConvert [Double,Int]
更不用说
次数的返回类型现在是
任何
,但无论如何,我的时代功能。我想我会在这里添加它,以免它可能有助于达成解决方案。所以侧面的问题:我如何能够将一个类/函数的上下文绑定类型传递给另一个,就像我正在尝试做的那样。解决方案我认为你做得比它需要的更难。
你需要证据表明这两个参数都是
数字
。随着证据的确立,这项工作就完成了。 Scala将采用数字扩大化结果是两种接收类型中更一般的。
def mult [T](a:T,b:T )(implicit ev:Numeric [T]):T =
ev.times(a,b)
如果你想获得更多的鸽友,你可以引入所需的暗示。然后阅读和理解起来更容易一些。
pre $ def $ mult [T:Numeric](a:T,b:T) :T = {
import Numeric.Implicits._
a * b
}
证明:
mult(2.3f,7)// res0:Float = 16.1
mult 8,2.1)// res1:Double = 16.8
mult(3,2)// res2:Int = 6
有关泛型类型和数值范围扩展的更多信息,请这个问题及其答案值得研究。
I am trying to write a generic weighted average function. I want to relax the requirements on the values and the weights being of the same type. ie, I want to support sequences of say:
(value:Float,weight:Int)
and(value:Int,weight:Float)
arguments and not just:(value:Int,weight:Int)
To do so, I first need to implement a function that takes two generic numerical values and returns their product.
def times[A: Numeric, B: Numeric](x: B, y: A): (A, B) : ??? = {...}
Writing the signature and thinking about the return type, made me realise that I need to define some sort of hierarchy for Numerics to determine the return type. ie
x:Float*y:Int=z:Float
,x:Float*y:Double=z:Double
.Now, Numeric class defines operations
plus
,times
, etc. only for arguments of the same type. I think I would need to implement a type:class NumericConverter[Numeirc[A],Numeric[B]]{ type BiggerType=??? }
so that I can write my times 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 the "bigger one" and feed it to
times()
.Am I on the right track? How would I "implement" the
BiggerType
?clearly I can't do something like:
type myType = if(...) Int else Float
as that is evaluated dynamically, so it worn't work.
I understand that I might be able to 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 the argument types.
Feel free to let me know if there is a whole easier way of doing this.
update:
this is what I came up with it.
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 silly as I will have to create implicits for both
IntDouble extends NumericsConvert[Int,Double]
and
DoubleInt extends NumericsConvert[Double,Int]
not to mention that the return type of
times
is nowAny
, but regardless, I am getting errors for my times functions. I thought I would add it here in case it might help with arriving at a solution. so side question: how I can pass context bound types of one class/function to another like I am trying to do in times.解决方案I think you're making this harder than it needs to be.
You need "evidence" that both parameters are
Numeric
. With that established let the evidence do the work. Scala will employ numeric widening so that the result is the more general of the two received types.def mult[T](a: T, b: T)(implicit ev:Numeric[T]): T = ev.times(a,b)
If you want to get a little fancier you can pull in the required implicits. Then it's a little easier to read and understand.
def mult[T: Numeric](a: T, b: T): T = { import Numeric.Implicits._ a * b }
Proof:
mult(2.3f , 7) //res0: Float = 16.1 mult(8, 2.1) //res1: Double = 16.8 mult(3, 2) //res2: Int = 6
For more on generic types and numeric widening, this question, and its answer, are worth studying.
这篇关于Scala:通用函数乘以不同类型的数字的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文