Scala:泛型函数乘以不同类型的数字
Scala: generic function multiplying Numerics of different types
我正在尝试编写一个通用的加权平均函数。
我想放宽对相同类型的值和权重的要求。即,我想支持 say 序列:(value:Float,weight:Int)
和 (value:Int,weight:Float)
参数而不仅仅是:(value:Int,weight:Int)
为此,我首先需要实现一个函数,该函数接受两个通用数值和 return 它们的乘积。
def times[A: Numeric, B: Numeric](x: B, y: A): (A, B) : ??? = {...}
写签名和思考 return 类型,让我意识到我需要为数值定义某种层次结构来确定 return 类型。即 x:Float*y:Int=z:Float
, x:Float*y:Double=z:Double
.
现在,Numeric class 定义操作 plus
、times
等,仅适用于相同类型的参数。我想我需要实现一个类型:
class NumericConverter[Numeirc[A],Numeric[B]]{
type BiggerType=???
}
这样我就可以将我的时间函数写成:
def times[A: Numeric, B: Numeric](x: B, y: A): (A, B) :
NumericConverter[Numeirc[A],Numeric[B]].BiggerType= {...}
并将 "smaller type" 转换为 "bigger one" 并将其提供给 times()
。
我走在正确的轨道上吗?我将如何 "implement" BiggerType
?
显然我不能做这样的事情:
type myType = if(...) Int else Float
因为它是动态评估的,所以它不起作用。
我知道我可以使用 Scalaz 等来做到这一点,但这是一个学术练习,我想了解 如何编写静态 return 类型的函数基于参数类型。
如果有更简单的方法,请随时告诉我。
更新:
这是我想出来的。
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)
这很愚蠢,因为我必须为两者创建隐式
IntDouble extends NumericsConvert[Int,Double]
和
DoubleInt extends NumericsConvert[Double,Int]
更不用说 times
的 return 类型现在是 Any
,但无论如何,我的时间函数都出现错误。我想我会在这里添加它,以防它有助于找到解决方案。所以附带问题:我如何将一个 class/function 的上下文绑定类型传递给另一个,就像我在 times.
中尝试做的那样
我认为你让这件事变得比需要的更难了。
你需要"evidence"两个参数都是Numeric
。有了这一点,让证据来完成工作。 Scala 将使用 numeric widening 以便结果是两种接收类型中更通用的一种。
def mult[T](a: T, b: T)(implicit ev:Numeric[T]): T =
ev.times(a,b)
如果你想变得更高级一点,你可以引入所需的隐含函数。那么阅读理解起来就容易一些了。
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
有关泛型类型和数字扩展的更多信息, 及其答案值得研究。
我正在尝试编写一个通用的加权平均函数。
我想放宽对相同类型的值和权重的要求。即,我想支持 say 序列:(value:Float,weight:Int)
和 (value:Int,weight:Float)
参数而不仅仅是:(value:Int,weight:Int)
为此,我首先需要实现一个函数,该函数接受两个通用数值和 return 它们的乘积。
def times[A: Numeric, B: Numeric](x: B, y: A): (A, B) : ??? = {...}
写签名和思考 return 类型,让我意识到我需要为数值定义某种层次结构来确定 return 类型。即 x:Float*y:Int=z:Float
, x:Float*y:Double=z:Double
.
现在,Numeric class 定义操作 plus
、times
等,仅适用于相同类型的参数。我想我需要实现一个类型:
class NumericConverter[Numeirc[A],Numeric[B]]{
type BiggerType=???
}
这样我就可以将我的时间函数写成:
def times[A: Numeric, B: Numeric](x: B, y: A): (A, B) :
NumericConverter[Numeirc[A],Numeric[B]].BiggerType= {...}
并将 "smaller type" 转换为 "bigger one" 并将其提供给 times()
。
我走在正确的轨道上吗?我将如何 "implement" BiggerType
?
显然我不能做这样的事情:
type myType = if(...) Int else Float
因为它是动态评估的,所以它不起作用。
我知道我可以使用 Scalaz 等来做到这一点,但这是一个学术练习,我想了解 如何编写静态 return 类型的函数基于参数类型。
如果有更简单的方法,请随时告诉我。
更新:
这是我想出来的。
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)
这很愚蠢,因为我必须为两者创建隐式
IntDouble extends NumericsConvert[Int,Double]
和
DoubleInt extends NumericsConvert[Double,Int]
更不用说 times
的 return 类型现在是 Any
,但无论如何,我的时间函数都出现错误。我想我会在这里添加它,以防它有助于找到解决方案。所以附带问题:我如何将一个 class/function 的上下文绑定类型传递给另一个,就像我在 times.
我认为你让这件事变得比需要的更难了。
你需要"evidence"两个参数都是Numeric
。有了这一点,让证据来完成工作。 Scala 将使用 numeric widening 以便结果是两种接收类型中更通用的一种。
def mult[T](a: T, b: T)(implicit ev:Numeric[T]): T =
ev.times(a,b)
如果你想变得更高级一点,你可以引入所需的隐含函数。那么阅读理解起来就容易一些了。
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
有关泛型类型和数字扩展的更多信息,