我想实现一个通用加权平均函数,它放宽了对值的要求,并且权重属于同一类型 . 即,我想支持以下序列: (value:Float,weight:Int) 和 (value:Int,weight:Float) 参数而不仅仅是: (value:Int,weight:Int) . [见到我之前的question在此期间 . ]
这就是我目前所拥有的:
def weightedSum[A: Numeric](weightedValues: GenSeq[(A, A)]): (A, A)
def weightedAverage[A: Numeric](weightedValues: GenSeq[(A, A)]): A = {
val (weightSum, weightedValueSum) = weightedSum(weightedValues)
implicitly[Numeric[A]] match {
case num: Fractional[A] => ...
case num: Integral[A] => ...
case _ => sys.error("Undivisable numeric!")
}
}
如果我喂它,例如:
val values:Seq[(Float,Float)] = List((1,2f),(1,3f))
val avg= weightedAverage(values)
但是,如果我没有从 Int 到 Float 的权重"upcast":
val values= List((1,2f),(1,3f)) //scalac sees it as Seq[(Int,Float)]
val avg= weightedAverage(values)
Scala编译器会告诉我:
错误:无法找到Numeric类型的证据参数的隐含值[AnyVal] val avg = weightedAverage(values)
有办法绕过这个吗?
我尝试编写一个 NumericCombine 类,我用 A 和 B 参数化了"combines"类型"common"类型 AB (例如,组合 Float 和 Int 给你 Float ):
abstract class NumericCombine[A: Numeric, B: Numeric] {
type AB <: anyval>
def fromA(x: A): AB
def fromB(y: B): AB
val num: Numeric[AB]
def plus(x: A, y: B): AB = num.plus(fromA(x), fromB(y))
def minus(x: A, y: B): AB = num.minus(fromA(x), fromB(y))
def times(x: A, y: B): AB = num.times(fromA(x), fromB(y))
}
我设法使用类型类型模式编写简单的 times 和 plus 函数,但由于 NumericCombine 引入了路径依赖类型 AB ,"composing"这些类型证明比我预期的更难 . 请查看this问题以获取更多信息,并参见here以完整实施 NumericCombine .
Update
作为another question(完整的工作演示here)的答案已经获得了一个令人满意的解决方案,但考虑到@ziggystar在discussion中提出的要点,仍然有一些设计改进的空间 .