2016-04-06 4 views
2

Есть ли способ параметризации типа через значение в scala? Например, параметризовать матрицу с его размер так что-то вроде ...Параметризация размера в Scala

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

val m3 = m1 multiply m2 

будет сгенерировано исключение, потому что вы не можете умножить матрицу [2,3] на [5,1]?

Это также было бы полезно при реализации других типов, таких как кортежи или векторы. Кто-нибудь знает, как это достичь?

+1

Это называется зависимой типизацией, а Scala ее не имеет. [Безжизненный] (https://stackoverflow.com/questions/28287612/how-to-require-typesafe-constant-size-array-in-scala) может помочь вам в этом. –

+0

В этом случае он не должен зависеть (печатать). Вы можете определить иерархию типов с использованием чисел Peano и до тех пор, пока они совпадут с вашим кодом, и в противном случае это не произойдет. –

ответ

4

Использование чисел Пеано мы можем определить типы, все натуральные числа, начиная с 0. При этом они все подтипы Nat но _1 и _2 являются различные типы, поэтому они не могут быть использованы вместо друг друга без отклонений.

Определение натуральных чисел:

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 

Матрица инвариантно в его типах параметров:

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

Функция умножения также инвариантно:

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] 

Компилятор будет делать проверки для вас, размеры совпадающие:

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

размеры не совпадают, компилировать ошибки времени гораздо лучше, чем время выполнения:

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")) 
                ^

Я был слишком ленив, чтобы написать фактическую реализацию умножения, следовательно ignoreThis заполнителем.

+0

Ooh wow awesome! Вы используете какие-либо библиотеки? –

+0

Это чистая Scala, никаких специальных библиотек. Я уверен, что должны быть более правильные и полные реализации типов математических математических структур и операций там. –

+0

Это здорово показать, как Scala поддерживает искажения, необходимые для этого, но эти сообщения об ошибках ... непрозрачны. И шаблон должен был сделать Матрикс [_100, _256], или что-то было бы огромным. –

Смежные вопросы