2013-05-13 26 views
8

我試圖編寫代碼來表示Scala中的多項式。我需要這個代碼是類型多態的,所以我使用implicits來處理不同的類型。我有:在類中使用隱式對象

case class Mono[T](degree: Int, coeff: T) { 
    def Degree: Int = return degree 
    def Coeff: T = return coeff 
} 

class Poly[T](private val terms: List[Mono[T]]) { 

    trait Semiring[T] { 
    def add(x:T, y:T): T 
    def mul(x:T, y:T): T 
    def exponent(x: T, n:Int): T 
    val unitA: T 
    } 

    implicit object IntSemiring extends Semiring[Int] { 
    def add(x: Int, y: Int): Int = x+y 
    def mul(x: Int, y: Int): Int = x*y 
    def exponent(x: Int, n:Int): Int = if(n==0) 1 else x*exponent(x, n-1) 
    val unitA: Int = 0 
    } 

    implicit object SetSemiring extends Semiring[Set[Int]] { 
    def add(x: Set[Int], y: Set[Int]): Set[Int] = x.union(y) 
    def mul(x: Set[Int], y: Set[Int]): Set[Int] = x.intersect(y) 
    def exponent(x: Set[Int], n: Int): Set[Int] = x 
    val unitA: Set[Int] = Set() 
    } 

    def eval(x: T)(implicit r: Semiring[T]): T = { 
    var termlist = terms 
    var sum = r.unitA 
    var expression = terms 
    while(!termlist.isEmpty) { 
     val term = expression.head 
     val power = r.exponent(x, term.Degree) 
     val termval = r.mul(power, term.Coeff) 
     sum = r.add(sum, termval) 
     termlist = termlist.tail 
    } 
    return sum 
    }  

    def add(that: Poly[T])(implicit r: Semiring[T]): Poly[T] = ... 

    def mul(that: Poly[T])(implicit r: Semiring[T]): Poly[T] = ... 
} 

爲了簡潔起見,我在這裏剔除了一些函數。這編譯好,但當我嘗試和使用它時,我得到一些奇怪的錯誤:

scala> val p1 = new Poly(List(Mono(0,1),Mono(1,2),Mono(2,1))) 
p1: Poly[Int] = [email protected] 
scala> p1 eval 3 
<console>:9: error: could not find implicit value for parameter r: p1.Semiring[Int] 
       p1 eval 3 
       ^

我不知道如何解決它。我是否在錯誤的地方定義了隱式對象?我試圖在課堂之外移動它們,但是編譯器失敗了。有什麼我需要做的,以使其正常工作?

+0

你可能想在石塔看上去太:https://github.com/non/spire:「石塔是其目的是爲斯卡拉數字圖書館通用,快速,準確。 Spire通過使用諸如專業化,宏,類型類型和含義等特性,努力反駁有關性能和精度權衡的傳統觀點。主要目標是允許開發人員編寫高效的數字代碼,而不必「烘烤」特定的數字表示。在大多數情況下,使用Spire的專用類型類的泛型實現與相應的直接實現完全相同。「 – 2016-05-14 14:05:54

回答

15

隱式解析是在您調用該函數的位置完成的,而不是您定義它的位置。調用p1.eval之前,您應該導入implicits:

val p1 = new Poly(List(Mono(0,1),Mono(1,2),Mono(2,1))) 
import p1._ 
p1 eval 3 

由於您的implicits是不是真的綁定到保利的一個實例,你可以定義他們聚外部。

如果你不希望明確導入Semiring implicits,您可以在自斯卡拉搜索在同伴對象匹配implicits的Semiring同伴對象定義他們時,他們缺少:

case class Mono[T](degree: Int, coeff: T) { 
    def Degree: Int = return degree 
    def Coeff: T = return coeff 
} 

class Poly[T](private val terms: List[Mono[T]]) { 
    def add(that: Poly[T])(implicit r: Semiring[T]): Poly[T] = ... 

    def mul(that: Poly[T])(implicit r: Semiring[T]): Poly[T] = ... 
} 

trait Semiring { 
    def add(x:T, y:T): T 
    def mul(x:T, y:T): T 
    def exponent(x: T, n:Int): T 
    val unitA: T 
} 

object Semiring { 
    implicit object IntSemiring extends Semiring[Int] { 
    def add(x: Int, y: Int): Int = x+y 
    def mul(x: Int, y: Int): Int = x*y 
    def exponent(x: Int, n:Int): Int = if(n==0) 1 else x*exponent(x, n-1) 
    val unitA: Int = 0 
    } 

    implicit object SetSemiring extends Semiring[Set[Int]] { 
    def add(x: Set[Int], y: Set[Int]): Set[Int] = x.union(y) 
    def mul(x: Set[Int], y: Set[Int]): Set[Int] = x.intersect(y) 
    def exponent(x: Set[Int], n: Int): Set[Int] = x 
    val unitA: Set[Int] = Set() 
    } 
} 

然後你不需要再導入它們:

val p1 = new Poly(List(Mono(0,1),Mono(1,2),Mono(2,1))) 
p1 eval 3 
+0

我明白了。是否有任何方法可以自動實現,而不必顯式調用導入p1._? – Joe 2013-05-13 12:48:49

+0

請參閱已編輯我的答案的版本:) – 2013-05-13 13:07:08

+0

謝謝,這是做的伎倆。 – Joe 2013-05-13 13:09:26