Использование чисел Пеано мы можем определить типы, все натуральные числа, начиная с 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
заполнителем.
Это называется зависимой типизацией, а Scala ее не имеет. [Безжизненный] (https://stackoverflow.com/questions/28287612/how-to-require-typesafe-constant-size-array-in-scala) может помочь вам в этом. –
В этом случае он не должен зависеть (печатать). Вы можете определить иерархию типов с использованием чисел Peano и до тех пор, пока они совпадут с вашим кодом, и в противном случае это не произойдет. –