2016-04-06 15 views
2

Gibt es trotzdem einen Parameter über einen Wert in scala zu parametrisieren? Zum Beispiel, um eine Matrix parametrisieren damit Größe ist so etwas wie ...Größen-Parametrierung in Scala

val m1 = new Matrix[2,3]() 
val m2 = new Matrix[5,1]() 

val m3 = m1 multiply m2 

würde eine Ausnahme aus, weil die Sie sich nicht vermehren können eine [2,3] Matrix durch eine [5,1]?

Dies wäre auch nützlich beim Implementieren anderer Typen wie Tupel oder Vektoren. Kennt jemand einen Weg, dies zu erreichen?

+1

Dies wird als abhängige Typisierung bezeichnet, und Scala hat es nicht. [Shapeless] (https://stackoverflow.com/questions/28287612/how-to-require-typesafe-constant-size-array-in-scala) kann Sie dort hinbringen. –

+0

In diesem Fall muss es nicht abhängig sein (tippen). Sie können eine Hierarchie von Typen definieren, die Peano-Nummern verwenden, und so lange sie übereinstimmen, würde Ihr Code kompilieren, andernfalls nicht. –

Antwort

4

Mit Peano Zahlen, die wir Typen definieren, die alle von 0 beginnend natürliche Zahlen sind Hier sind sie alle Subtypen von Nat aber _1 und _2 unterschiedliche Typen sind, so können sie nicht ohne Varianz anstelle voneinander verwendet werden.

definieren natürliche Zahlen:

scala> sealed trait Nat 
defined trait Nat 

scala> sealed trait _0 extends Nat 
defined trait _0 

scala> sealed trait Succ[N <: Nat] extends Nat 
defined trait Succ 

scala> type _1 = Succ[_0] 
defined type alias _1 

scala> type _2 = Succ[_1] 
defined type alias _2 

Matrix in seinen Parametertypen unveränderlich ist:

scala> case class Matrix[A <: Nat, B <: Nat](ignoreThis: String) 
defined class Matrix 

Die Funktion Multiplikation sind auch invariant:

scala> def multiply[R1 <: Nat, C1 <: Nat, C2 <: Nat](m1: Matrix[R1, C1], m2: Matrix[C1, C2]) = Matrix[R1, C2](m1.ignoreThis + m2.ignoreThis) 
multiply: [R1 <: Nat, C1 <: Nat, C2 <: Nat](m1: Matrix[R1,C1], m2: Matrix[C1,C2])Matrix[R1,C2] 

Compiler werden die Kontrollen tun für Sie stimmen die Maße überein:

scala> multiply(Matrix[_1, _2]("one"), Matrix[_2, _1]("two")) 
res0: Matrix[_1,_1] = Matrix(onetwo) 

Dimensionen nicht übereinstimmen, Zeitfehler kompilieren sind viel besser als Laufzeit:

scala> multiply(Matrix[_1, _2]("one"), Matrix[_1, _1]("two")) 
<console>:19: error: type mismatch; 
found : Matrix[_1(in object $iw),_2] 
    (which expands to) Matrix[Succ[_0],Succ[Succ[_0]]] 
required: Matrix[_1(in object $iw),Succ[_ >: _0 with _1(in object $iw) <: Nat]] 
    (which expands to) Matrix[Succ[_0],Succ[_ >: _0 with Succ[_0] <: Nat]] 
Note: _2 <: Succ[_ >: _0 with _1 <: Nat], but class Matrix is invariant in type B. 
You may wish to define B as +B instead. (SLS 4.5) 
     multiply(Matrix[_1, _2]("one"), Matrix[_1, _1]("two")) 
          ^
<console>:19: error: type mismatch; 
found : Matrix[_1(in object $iw),_1(in object $iw)] 
    (which expands to) Matrix[Succ[_0],Succ[_0]] 
required: Matrix[Succ[_ >: _0 with _1(in object $iw) <: Nat],_1(in object $iw)] 
    (which expands to) Matrix[Succ[_ >: _0 with Succ[_0] <: Nat],Succ[_0]] 
Note: _1 <: Succ[_ >: _0 with _1 <: Nat], but class Matrix is invariant in type A. 
You may wish to define A as +A instead. (SLS 4.5) 
     multiply(Matrix[_1, _2]("one"), Matrix[_1, _1]("two")) 
                ^

Ich war zu faul tatsächlichen Multiplikation Implementierung daher ignoreThis Platzhalter zu schreiben.

+0

Ooh wow awesome! Benutzt du irgendwelche Bibliotheken? –

+0

Das ist reine Scala, keine speziellen Bibliotheken. Ich bin mir sicher, dass es mehr richtige und vollständige Implementierungen von typsicheren mathematischen Strukturen und Operationen geben muss. –

+0

Das ist cool, wenn man zeigt, wie Scala die Verdrehungen unterstützt, die dazu nötig sind, aber diese Fehlermeldungen sind ... undurchsichtig. Und das für Matrix [_100, _256] benötigte Programm sollte immens sein. –