2012-02-12 18 views
7

我對Scala很新穎。我想寫幾個在某些操作(+, - ,*)下關閉的數學對象(Complex,Polynomial等),以便可以在泛型中使用它們,並且可以使用隱式轉換。實現編號

我似乎已經解決了第一點。

trait GroupUnderAddition[T] { 
    def + (t : T) : T 
} 

case class Real(d : Double) extends GroupUnderAddition[Real] { 
    def + (r : Real) = Real(d + r.d) 
} 

case class Complex(re : Double, im : Double) extends GroupUnderAddition[Complex] { 
    def + (c : Complex) = Complex(re + c.re, im + c.im) 
} 

object Test { 
    implicit def real_to_complex(r : Real) = Complex(r.d, 0) 

    def test[G <: GroupUnderAddition[G]](a : G, b : G) = a + b 

    def main(args : Array[String]) { 
    println(test(Real(5), Real(2))) 
    } 
} 

現在,我怎麼能寫測試(),使

test(Real(5), Complex(2, 1)) 

收益複合物(7,1)?

回答

2

主要思想是所有GroupUnderAddition都不兼容,所以如果您似乎想要使用複雜的代數,我會建議構建一個包括GoupUnderAddition的超類。但是不建議使它成爲一個案例類(見警告,如果你有一個case class延伸的case class

trait GroupUnderAddition[T] { 
    def + (t : T) : T 
} 

class ComplexAlgebra(_re:Double, _im:Double) extends(GroupUnderAddition[ComplexAlgebra]) { 
    val re = _re 
    val im = _im  
    def + (c : ComplexAlgebra) = new ComplexAlgebra(re + c.re, im + c.im) 
} 

case class Real(d : Double) extends ComplexAlgebra(d, 0) 

case class Complex(real : Double, imaginary : Double) extends ComplexAlgebra(real,imaginary) 

object Test { 

    def test(a : ComplexAlgebra, b : ComplexAlgebra) = a + b 

    def main(args : Array[String]) { 
    println(test(Real(5), Real(2))) 
    } 
} 
+0

當然,我能做到這一點,但我想保持仿製藥。做你的方式,如果我想叫測試與兩個多項式,我需要重寫整個事情。 – 2012-02-12 12:14:20

+0

是的,但你有2個不同的問題,第一個是要創建通用'GroupUnderAddition'這將實現方法'+'。在另一方面,你想有一個特定的'GroupUnderAddition'實現2種不同的數字:'Real'和'Complex'。所以,你必須到另一個絕招,這就是爲什麼你想過'隱def'但在你的情況我沒有找到這個解決方案。 – 2012-02-12 13:43:48

1

的問題是,implicit def不考慮參數轉換,除非你指定的方法定義這樣做。

因此,如果您有類似Real(5).foofoo的內容僅針對複雜性定義,則implicit def將適用於此功能。

如果你有類似的方法:def foo(c : Complex) = ...你可能不會用foo(Real(5))來代替它。

如果要應用隱式轉換,則必須指定您的方法以使其參數可以轉換。對於上述foo方法,你可以做這樣的:

def foo[T](c : T)(implicit ct : T => Complex) = ...` 

然後,它是有效的調用foo(Real(5))和轉換將被使用。

適合您的具體問題,你可以寫的測試方法是這樣的:

def test[G <: GroupUnderAddition[G],T](a : T, b : G)(implicit ag: T => G) = a + b 

通過指定,即隱式轉換從TG,應考慮到,你讓test方法現在接受test(Real(5), Complex(2,1))

但是,它不會以其他方式工作。所以你還不能用test(Complex(2,1), Real(5))來調用它,因爲沒有第二個參數的隱式轉換。

直截了當地解釋這兩個轉換將它寫這樣的:

def test[G <: GroupUnderAddition[G],T1, T2](a : T1, b : T2)(implicit ag: T1 => G, bg: T2 => G) = a + b 

不幸的是,調用此方法類似於上面編譯的時候莫名其妙地派生AnyG。我現在不知道如何解決這個問題,並且我發佈了這個答案,希望別人能夠填補這個難題。

鑑於上述情況最終定義,你至少可以調用任何一種方式的方法,指定完整的類型時:

println(test[Complex,Real,Complex](Real(5), Complex(2, 1))) 
println(test[Complex,Complex,Real](Complex(2,1), Real(5))) 
1

這裏真正的問題是,你正在做的(不正確)假設test(Real(5), Complex(2, 1))根據你寫的內容以任何方式定義好。考慮以下幾點:

case class Word(s : String) extends GroupUnderAddition[Word] { 
    def +(w : Word) = Word(s + w.s) 
} 

這完全滿足你的「GroupUnderAddition」的定義,但它是沒有意義的嘗試添加一個字(「你好」),以一個真正的(2)。結果是什麼?

你正在嘗試以編碼是一個更大的領域內的具體加法運算符 - 它似乎多項式對C域 - 和指定的這個特定的子羣的加法運算下封閉。 ChrisJamesC的方法可以很好地擴展到多項式環,它可以捕捉你想要的東西。

+0

考慮到我有一個隱式的實數=>複數函數,測試(實數(5),複數(2,1))是很好的定義。我不想爲GroupUnderAddition的任何兩個孩子做這項工作。 – 2012-02-13 15:24:15