Scala 中的大小参数化

Size Parameterization in Scala

在 Scala 中是否有通过值参数化类型的方法?例如,要用它的大小参数化一个矩阵,就像...

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

val m3 = m1 multiply m2

将无法编译,因为您不能将 [2,3] 矩阵乘以 [5,1]?

这对于实现其他类型(例如元组或向量)也很有用。有谁知道实现这个的方法吗?

使用Peano数我们可以定义所有类型都是从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 占位符。