假设我正在用 C# 编写一个线性代数库,并且我想实现矩阵乘法。当然,如果
A
的列数与 B
的行数一样多,则两个矩阵 AB
和 A
只能相乘形成 B
。因此,人们通常会在乘法的定义中包含一个参数验证步骤,在不匹配的情况下抛出错误。这就是我最近一直在使用的 MathNet.Numerics 库中的实现方式。但是,如果矩阵维数是类型定义的一部分不是更好吗?
如果矩阵维度是类型定义的一部分,那么可以在编译时而不是运行时捕获这种维度不匹配。这对于在其他上下文中约束矩阵的形状也很有用,例如在实现仅为方阵定义的数学函数时。特别是,不可能因为忘记验证矩阵维度而引入错误。
但是,要实现这一点,我们需要某种语言机制,让我们定义一个无限(至少在理论上)的类族,所有形式都是
MatrixMxN
,其中 M
和 N
是描述矩阵维度的自然数。据我所知,这在 C# 中是不可能的,但也许有某种方法?我们可以定义一个泛型类 Matrix<T1,T2>
,但除非我们能为每个自然数创建一种类型 T
,否则我不知道这将如何帮助我们实现目标。我注意到一些函数式语言有一种叫做“类型级自然数”的东西,这似乎与后一个想法相对应。
那么,有没有一种方法可以实现我上面描述的功能呢?如果不是 C#,那么其他语言呢?
就 C# 而言,不存在这样的机制。如果有的话,Microsft 自己就不必这样做来定义
Tuple<T>
的各种类型参数计数
public static Tuple<T1> Create<T1>(T1 item1) {
return new Tuple<T1>(item1);
}
public static Tuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2) {
return new Tuple<T1, T2>(item1, item2);
}
public static Tuple<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3) {
return new Tuple<T1, T2, T3>(item1, item2, item3);
}
public static Tuple<T1, T2, T3, T4> Create<T1, T2, T3, T4>(T1 item1, T2 item2, T3 item3, T4 item4) {
return new Tuple<T1, T2, T3, T4>(item1, item2, item3, item4);
}
public static Tuple<T1, T2, T3, T4, T5> Create<T1, T2, T3, T4, T5>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) {
return new Tuple<T1, T2, T3, T4, T5>(item1, item2, item3, item4, item5);
}
public static Tuple<T1, T2, T3, T4, T5, T6> Create<T1, T2, T3, T4, T5, T6>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6) {
return new Tuple<T1, T2, T3, T4, T5, T6>(item1, item2, item3, item4, item5, item6);
}
public static Tuple<T1, T2, T3, T4, T5, T6, T7> Create<T1, T2, T3, T4, T5, T6, T7>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7) {
return new Tuple<T1, T2, T3, T4, T5, T6, T7>(item1, item2, item3, item4, item5, item6, item7);
}
public static Tuple<T1, T2, T3, T4, T5, T6, T7, Tuple<T8>> Create<T1, T2, T3, T4, T5, T6, T7, T8>(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8) {
return new Tuple<T1, T2, T3, T4, T5, T6, T7, Tuple<T8>>(item1, item2, item3, item4, item5, item6, item7, new Tuple<T8>(item8));
}
为了获得更多乐趣,请查看整个 Tuple.cs 源文件。