在之前的问题中,我想知道 C# 中是否有某种方法可以将矩阵维数实现为类型级属性。也就是说,我希望能够声明一个
Matrix<M, N>
形式的通用类族,其中 M
和 N
是自然数。最终目标是在编译时进行维数检查,因此,例如,尝试将 3x3 矩阵乘以 2x3 矩阵应该会产生编译时错误,或者具有仅接受方阵的函数 (Matrix<M, M>
) .
不幸的是,这在 C# 中似乎不可能,问题是泛型类型
M
中的 N
和 Matrix<M, N>
必须是类型,而不是整数。然而,其他一些语言似乎有解决这个问题的机制:
一些函数式语言,例如 Haskell,可以定义类型级别的自然数。如果这在 C# 中是可能的,那么也应该可以定义
Matrix<M, N>
,其中 M
和 N
是类型级别的自然数。我对 F# 不太了解,但这个答案似乎表明这在 F# 中也是可能的。
在 C++ 中,可以使用带有非类型模板参数的模板。如果我理解正确的话,代码中实际使用的特定大小的类会在编译时生成。
现在,由于 C# 和 F# 都是 .NET 语言,我主要对上面的第 1 点感兴趣。是否可以在 F# 中实现我需要的类型,然后将它们作为库提供给我的应用程序?最好的情况是我可以在 F# 中仅定义类型级别的自然数,然后在 C# 中使用它们来定义
Matrix<M, N>
。
我会使用带有静态成员的接口来完成此操作。在 F# 中,您可以像这样定义类型级自然数:
namespace TypeLevelNatural
#nowarn "3535" // allow interfaces with static abstract members
/// Type-level interface that all natural numbers must implement.
type Natural =
static abstract Size : int
/// Type zero.
type Zero =
interface Natural with
static member Size = 0
/// Type-level successor function.
type Successor<'t when 't :> Natural>() =
interface Natural with
static member Size = 't.Size + 1
/// Define 1, 2, 3, ...
type One() = inherit Successor<Zero>()
type Two() = inherit Successor<One>()
type Three() = inherit Successor<Two>()
type Four() = inherit Successor<Three>()
那么在C#中,你可以这样定义一个矩阵:
class Matrix<NRows, NCols>
where NRows : Natural
where NCols : Natural
{
public Matrix() { }
public double[,] Values = new double[NRows.Size, NCols.Size];
}
使用示例:
var matrix = new Matrix<Two, Three>();
for (int iRow = 0; iRow < matrix.Values.GetLength(0); iRow++)
for (int iCol = 0; iCol < matrix.Values.GetLength(1); iCol++)
Console.WriteLine(matrix.Values[iRow, iCol]);