2013-05-13 12 views
8

Sto provando a scrivere codice per rappresentare i polinomi all'interno di Scala. Ho bisogno che questo codice sia di tipo polimorfico, quindi uso impliciti per trattare tipi diversi. Ho:Utilizzo di oggetti impliciti nelle classi

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

Ho interrotto alcune funzioni per brevità lì. Questo compila benissimo ma quando provo e lo uso io ottenere alcuni strani errori:

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 
       ^

Non sono sicuro di come risolvere il problema. Sto definendo gli oggetti impliciti nel posto sbagliato? Ho provato a spostarli fuori dalla classe, ma poi il compilatore fallisce. C'è qualcos'altro che devo fare per farlo funzionare correttamente?

+0

si potrebbe desiderare di guardare troppo Spire: https://github.com/non/spire: "Spire è una libreria numerico per Scala, che è destinato ad essere generico, veloce e preciso Utilizzando funzioni come specializzazione, macro, classi di tipi e impliciti, Spire lavora sodo per sfidare la saggezza convenzionale intorno alle prestazioni e ai compromessi di precisione. Uno degli obiettivi principali è consentire agli sviluppatori di scrivere codice numerico efficiente senza dover "inserire" particolari rappresentazioni numeriche. Nella maggior parte dei casi, le implementazioni generiche che utilizzano le classi di tipo specializzate di Spire si comportano in modo identico alle corrispondenti implementazioni dirette. " –

risposta

15

La risoluzione implicita viene eseguita nel punto in cui si chiama la funzione, non dove la si definisce. Si dovrebbe importare i impliciti prima di chiamare p1.eval:

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

Dal momento che i impliciti non sono realmente legati a un'istanza di Poly, è possibile definire al di fuori Poly.

Se non si desidera importare esplicitamente i Semiring impliciti, è possibile definire l'oggetto associato di Semiring dal Scala ricerca di impliciti corrispondenti nell'oggetto compagno quando essi sono mancanti:

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() 
    } 
} 

Poi non è necessario importare più di loro:

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

.Vedo un modo per far sì che accada automaticamente, senza che io debba chiamare esplicitamente l'importazione p1._? – Joe

+0

Vedere la modifica versione della mia risposta :) –

+0

Grazie, questo è il trucco. – Joe