2010-02-16 9 views
6

Je suis très nouveau à Scala.Scala: Contrainte sur le type de classe générique

Je souhaite implémenter une classe de matrice générique "class Matrix [T]". La seule contrainte sur T devrait être que T devrait implémenter un "+" et un "*" mothod/fonction. Comment vais-je faire cela?

Par exemple, je veux pouvoir utiliser à la fois Int, Double et mes propres types définis, par ex. Complexe

Je pensais quelque chose le long des lignes:

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 
} 

Tout contrôles de type, mais je ne peux toujours pas instancier une matrice. Est-ce que je manque un constructeur implicite? Comment ferais-je cela? Ou ai-je complètement tort de ma méthode?

Merci à l'avance Troels

Répondre

4

a finalement trouvé la réponse :-) Je pense que je n'étais pas loin dans mon premier essai . Ici, il va: (écrit pour 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 
} 

Maintenant, je peux faire des choses comme:

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

Vous pouvez utiliser Numeric pour Scala 2.8 pour cela. C'est décrire here. Il remplacerait MatrixElement et ses mises en œuvre:

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

I considéré numérique. Mais je ne vois pas vraiment comment cela fonctionnerait pour mes propres types, par ex. Complexe. Je pense que Complex devrait alors étendre Numeric. Ce qui d'abord exigerait que j'implémente beaucoup plus de méthodes que juste + et *. Parmi ces commandes - Autant que je sache, il n'y a pas d'ordre strict sur les nombres complexes. Le point clé est que j'ai besoin de Matrix pour travailler sur tous les types qui remplissent uniquement les méthodes + et * sont implémentées. –

+0

Il y a beaucoup de méthodes à implémenter si vous avez seulement besoin de + et *. Mais vous pouvez toujours créer quelque chose comme Numeric avec ces deux méthodes. Cela devrait être deux beaucoup de travail. (Et peut-être revenir plus tard et le remplacer par Numeric si cela vaut la peine.) –

+1

@troels Vous pouvez toujours commander par la partie réelle, ou tout simplement retourner "0" pour toutes les comparaisons. Et vous pouvez toujours "implémenter" les méthodes avec 'error (" Undefined method ")'. Notez, cependant, que 'Complex' ne serait pas _extend_' Numeric'. Au lieu de cela, il y aurait une instance de 'Numeric [Complexe]'. –

2

Voici comment la solution Numeric regarderait:

// ': 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: Numérique [T]' devrait être 'T: Numeric'. Est-ce que vous écrivez ceci sans REPL? :-) –

+0

Oups! M'a surpris :) – retronym