2010-02-16 16 views
6

Sono molto nuovo di Scala.Scala: vincolo sul tipo di classe generico

Voglio implementare una classe matrice generica "classe Matrix [T]". L'unico vincolo su T dovrebbe essere che T dovrebbe implementare un "+" e una "*" forma/funzione. Come procedo a fare questo?

Ad esempio, desidero essere in grado di utilizzare sia Int, Double, sia i miei tipi definiti ad es. Complesso

Stavo pensando qualcosa del tipo:

class Matrix[T <: MatrixElement[T]](data: Array[Array[T]]) { 
    def *(that: Matrix) = ..// code that uses "+" and "*" on the elements 
} 
abstract class MatrixElement[T] { 
    def +(that: T): T 
    def *(that: T): T 
} 
implicit object DoubleMatrixElement extends MatrixElement[Double]{ 
    def +(that: Double): Double = this + that 
    def *(that: Double): Double = this * that 
} 
implicit object ComplexMatrixElement extends MatrixElement[Complex]{ 
    def +(that: Complex): Complex = this + that 
    def *(that: Complex): Complex = this * that 
} 

Tutto Tipo controlli, ma non riesco ancora a un'istanza di una matrice. Mi manca un costruttore implicito? Come potrei fare per farlo? O mi sbaglio del mio metodo?

Grazie in anticipo Troels

risposta

4

finalmente trovato la risposta :-) Penso che non ero poi così lontano nel mio primo tentativo . qui va: (scritto per scala 2,8)

trait MatrixElement[T] { 
    def +(that: T): T 
    def *(that: T): T 
} 

object MatrixElement { 
    implicit def intToMatrixElement(x : Int) = new MatrixElement[Int] { 
     def +(y : Int) = x + y 
     def *(y : Int) = x * y 
    } 
    implicit def doubleToMatrixElement(x : Double) = new MatrixElement[Double] { 
     def +(y : Double) = x + y 
     def *(y : Double) = x * y 
    } 
    implicit def complexToMatrixElement(x : Complex) = new MatrixElement[Complex] { 
     def +(y : Complex) = x + y 
     def *(y : Complex) = x * y 
    } 
} 

class Matrix[T <% MatrixElement[T] : ClassManifest ](d: Array[Array[T]]) { 
    def *(that: Matrix) = ..// code that uses "+" and "*" on the elements 
} 

ora posso fare cose come:

scala> new Matrix(Array(Array(1,0),Array(0,1))) 
res0: Matrix[Int] = 
1 0 
0 1 

scala> new Matrix(Array(Array(new Complex(0),new Complex(1)),Array(new Complex(1),new Complex(0)))) 
res9: Matrix[Complex] = 
(0.0,0.0i) (1.0,0.0i) 
(1.0,0.0i) (0.0,0.0i) 
4

È possibile utilizzare Numeric per Scala 2.8 per questo. È descritto here. Si sostituirebbe MatrixElement e le sue implementazioni:

class Matrix[T : Numeric](data: Array[Array[T]]) { 
    def *(that: Matrix[T]) = // 
} 
+0

ho considerato numerico. Ma non vedo davvero come funzionerebbe per i miei tipi, ad es. Complesso. Penserei che Complesso poi avrebbe bisogno di estendere Numeric. Quale prima di tutto richiederebbe l'implementazione di molti più metodi oltre a + e *. Tra questi ordini - Per quanto ne so non esiste un ordine rigoroso su numeri complessi. Il punto chiave è che ho bisogno di Matrix per lavorare su tutti i tipi che riempiono completamente i metodi + e *. –

+0

Ci sono molti metodi da implementare se hai solo bisogno di + e *. Ma puoi ancora creare qualcosa come Numeric con solo questi due metodi. Questo dovrebbe essere molto lavoro. (E magari tornare più tardi e sostituirlo con Numeric se ne vale la pena.) –

+1

@troels Puoi sempre ordinare per la parte reale, o semplicemente restituire "0" per tutti i confronti. E puoi sempre "implementare" i metodi con 'error (" metodo indefinito ")'. Si noti, tuttavia, che 'Complex' non sarebbe _extend_' Numerico'. Invece, ci sarebbe un'istanza di un 'Numerico [Complesso]'. –

2

Ecco come la soluzione Numeric apparirebbe:

// ': Numeric[T]' adds an implicit parameter to the constructor, 
// which allows T to be used in arithmetic expressions. 
class Matrix[T: Numeric](val data: Array[Array[T]]) { 
    def *(that: Matrix[T]) = { 
     val nt = implicitly[Numeric[T]] 
     import nt._ // This imports an Implicit View to allow operator syntax 

     this.data(0)(0) * that.data(0)(0) 
     // etc 
    } 
} 
+0

'T: Numeric [T]' dovrebbe essere 'T: Numeric'. Lo scrivi senza REPL? :-) –

+0

Oops! Catturato :) – retronym

Problemi correlati