2017-04-12 75 views
6

我想寫一個通用的加權平均函數。 我想放寬對相同類型的值和權重的要求。即,我想支持說的序列:(value:Float,weight:Int)(value:Int,weight:Float)參數,並不僅僅是:(value:Int,weight:Int)Scala:通用函數乘法不同類型的數字編號

要做到這一點,我首先需要實現的功能,它有兩個通用的數值,並返回他們的產品。

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

書寫簽名,並想返回類型,讓我意識到我需要定義某種層次的數值運算到確定返回類型。即x:Float*y:Int=z:Float,x:Float*y:Double=z:Double

現在,Numeric類僅爲相同類型的參數定義操作plustimes等。我想我會需要實現一個類型:

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= {...} 

和「較小型」轉換爲「大」,並給它到times()

我在正確的軌道上嗎?我將如何「實施」BiggerType?作爲動態評估,因此worn't工作

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

清楚,我不能這樣做。

我知道我可以這樣做使用Scalaz等,但這是一個學術練習,我想了解如何編寫一個基於參數類型靜態返回類型的函數。

隨時讓我知道是否有一個更簡單的方法來做到這一點。

更新

這是我想出了它。

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] 

不implicits提及的times返回類型現在是Any,但無論如何,我的時代功能出現錯誤。我想我會在這裏添加它,以免它可能有助於達成解決方案。所以旁邊的問題:我怎麼可以將一個類/函數的上下文綁定類型傳遞給另一個像我試圖在時間

回答

7

我認爲你要做的比想要的要難。

您需要「證據」,兩個參數都是Numeric。隨着證據的確立,這項工作就完成了。斯卡拉將採用numeric widening,以便結果是兩種接收類型中更普遍的結果。

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

如果你想得到一個小鴿友,你可以拉入必要的implicits。然後,閱讀和理解起來會更容易一些。

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 

更多關於泛型類型和數值加寬,this question,它的答案,都值得研究。

+0

呃!演員陣容完成了! :D – ShS

+0

隨時在您的答案中添加對http://scala-lang.org/files/archive/spec/2.11/06-expressions.html#value-conversions的引用,以解釋在幕後發生的事情。 – ShS

+0

好吧,所以我讓我的方法工作,但它有一個小問題。看看你是否可以幫助我解決它:http://stackoverflow.com/questions/43382282/scala-generic-weighted-average-function – ShS