2017-04-12 2 views
6

J'essaie d'écrire une fonction générique moyenne pondérée. Je veux assouplir les exigences sur les valeurs et les poids étant du même type. à-dire, je veux soutenir des séquences de dire: (value:Float,weight:Int) et (value:Int,weight:Float) arguments et non seulement: (value:Int,weight:Int)Scala: fonction générique multipliant Numérique de types différents

Pour ce faire, je dois d'abord mettre en œuvre une fonction qui prend deux valeurs numériques génériques et retourne leur produit.

def times[A: Numeric, B: Numeric](x: B, y: A): (A, B) : ??? = {...} 

Écrire la signature et la réflexion sur le type de retour, m'a fait réaliser que je dois définir une sorte de hiérarchie des Numerics pour déterminer le type de retour. c'est-à-dire x:Float*y:Int=z:Float, x:Float*y:Double=z:Double.

Maintenant, la classe numérique définit les opérations plus, times, etc. uniquement pour les arguments du même type. Je pense que je aurais besoin de mettre en œuvre un type:

class NumericConverter[Numeirc[A],Numeric[B]]{ 
type BiggerType=??? 
} 

pour que je puisse écrire mon temps fonction:

def times[A: Numeric, B: Numeric](x: B, y: A): (A, B) : 
NumericConverter[Numeirc[A],Numeric[B]].BiggerType= {...} 

et convertir le « type plus petit » au « plus gros » et nourrir à times().

Suis-je sur la bonne voie? Comment pourrais-je "implémenter" le BiggerType?

clairement que je ne peux pas faire quelque chose comme:

type myType = if(...) Int else Float 

comme cela est évalué de façon dynamique, il worn't travail. Je comprends que je pourrais être capable de le faire en utilisant Scalaz, etc. mais ceci est un exercice académique et je veux comprendre comment écrire une fonction qui renvoie statiquement un type basé sur les types d'arguments.

N'hésitez pas à me faire savoir s'il y a un moyen plus simple de le faire.

mise à jour:

ce que je suis venu avec elle.

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) 

qui est stupide que je vais devoir créer implicits pour les deux

IntDouble extends NumericsConvert[Int,Double] 

et

DoubleInt extends NumericsConvert[Double,Int] 

ne pas mentionner que le type de retour times est maintenant Any, mais peu importe, Je reçois des erreurs pour mes fonctions de temps. J'ai pensé que je l'ajouterais au cas où cela pourrait aider à arriver à une solution. donc côté question: comment je peux passer des types liés au contexte d'une classe/fonction à l'autre comme je suis en train de faire dans les temps.

Répondre

7

Je pense que vous rendez cela plus difficile que nécessaire.

Vous avez besoin de "preuves" que les deux paramètres sont Numeric. Avec cela établi laisser la preuve faire le travail. Scala utilisera numeric widening pour que le résultat soit le plus général des deux types reçus.

def mult[T](a: T, b: T)(implicit ev:Numeric[T]): T = 
    ev.times(a,b) 

Si vous voulez obtenir un petit colombophile, vous pouvez tirer les implicits nécessaires. Ensuite, c'est un peu plus facile à lire et à comprendre.

def mult[T: Numeric](a: T, b: T): T = { 
    import Numeric.Implicits._ 
    a * b 
} 

Preuve:

mult(2.3f , 7) //res0: Float = 16.1 
mult(8, 2.1) //res1: Double = 16.8 
mult(3, 2)  //res2: Int = 6 

Pour en savoir plus sur les types génériques et l'élargissement numérique, this question, et sa réponse, méritent d'être étudiés.

+0

Duh! le casting est fait en place! : D – ShS

+0

n'hésitez pas à ajouter des références à http://scala-lang.org/files/archive/spec/2.11/06-expressions.html#value-conversions dans votre réponse pour expliquer ce qui se passe derrière la scène. – ShS

+0

Ok, donc j'ai réussi à faire marcher ma méthode, mais il y a un petit problème avec ça. voyez si vous pouvez m'aider à le résoudre: http://stackoverflow.com/questions/43382282/scala-generic-weighted-average-function – ShS