Scala: função média ponderada genérica
Desejo implementar uma função média ponderada genérica que relaxe os requisitos de valores e pesos do mesmo tipo. ou seja, eu quero apoiar seqüências de dizer:(value:Float,weight:Int)
e(value:Int,weight:Float)
argumentos e não apenas:(value:Int,weight:Int)
. [Veja meu anteriorPergunta, questão na corrida para isso.]
Isto é o que eu tenho atualmente:
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!")
}
}
Isso funciona perfeitamente se eu alimentá-lo, por exemplo:
val values:Seq[(Float,Float)] = List((1,2f),(1,3f))
val avg= weightedAverage(values)
No entanto, se eu não "upcast" os pesos deInt
paraFloat
:
val values= List((1,2f),(1,3f)) //scalac sees it as Seq[(Int,Float)]
val avg= weightedAverage(values)
O compilador Scala me dirá:
erro: não foi possível encontrar um valor implícito para o parâmetro de evidência do tipo Numeric [AnyVal]
val avg = weightedAverage (values)
Existe uma maneira de contornar isso?
Eu tentei escrever umaNumericCombine
classe que eu parametrizei comA
eB
que "combina" os tipos em um tipo "comum"AB
(por exemplo, combinandoFloat
eInt
da-teFloat
):
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))
}
e eu consegui escrever simplestimes
eplus
funções baseadas nisso com o padrão tipeclass, mas desdeNumericCombine
introduz um tipo dependente de caminhoAB
, "compor" os tipos está se mostrando mais difícil do que eu esperava. Olhe paraesta pergunta para obter mais informações e consulteaqui para a plena implementação deNumericCombine
.
Atualizar
Uma solução um tanto satisfatória foi obtida como resposta aoutra pergunta (demonstração de trabalho completaaqui) no entanto, ainda há espaço para melhorias no projeto, levando em consideração os pontos levantados nodiscussão com @ziggystar.