Scala: función promedio ponderada genérica
Quiero implementar una función de promedio ponderado genérico que relaja el requisito de que los valores y los pesos sean del mismo tipo. es decir, quiero admitir secuencias de decir:(value:Float,weight:Int)
y(value:Int,weight:Float)
argumentos y no solo:(value:Int,weight:Int)
. [Ver mi anteriorpregunta en el período previo a esto.]
Esto es lo que tengo actualmente:
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!")
}
}
Esto funciona perfectamente si lo alimento, por ejemplo:
val values:Seq[(Float,Float)] = List((1,2f),(1,3f))
val avg= weightedAverage(values)
Sin embargo, si no "elevo" los pesos deInt
aFloat
:
val values= List((1,2f),(1,3f)) //scalac sees it as Seq[(Int,Float)]
val avg= weightedAverage(values)
El compilador de Scala me dirá:
error: no se pudo encontrar el valor implícito para el parámetro de evidencia de tipo Numérico [AnyVal]
val avg = weightedAverage (valores)
¿Hay alguna forma de evitar esto?
Tuve un intento de escribir unNumericCombine
clase que parametricé conA
yB
que "combina" los tipos en un tipo "común"AB
(por ejemplo, combinandoFloat
yInt
te dioFloat
):
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))
}
y logré escribir simpletimes
yplus
funciones basadas en esto con el patrón typeclass, pero desdeNumericCombine
introduce un tipo dependiente de la rutaAB
, "componer" los tipos está resultando ser más difícil de lo que esperaba. miraresta pregunta para obtener más información y veraquí para la plena implementación deNumericCombine
.
Actualizar
Se ha obtenido una solución algo satisfactoria como respuesta aotra pregunta (demostración de trabajo completaaquí) sin embargo, todavía hay margen para algunas mejoras de diseño teniendo en cuenta los puntos planteados en eldiscusión con @ziggystar.