我可以在 F# 中定义类型级自然数,然后在 C# 中使用它们吗?

问题描述 投票:0回答:1

之前的问题中,我想知道 C# 中是否有某种方法可以将矩阵维数实现为类型级属性。也就是说,我希望能够声明一个

Matrix<M, N>
形式的通用类族,其中
M
N
是自然数。最终目标是在编译时进行维数检查,因此,例如,尝试将 3x3 矩阵乘以 2x3 矩阵应该会产生编译时错误,或者具有仅接受方阵的函数 (
Matrix<M, M>
) .

不幸的是,这在 C# 中似乎不可能,问题是泛型类型

M
中的
N
Matrix<M, N>
必须是类型,而不是整数。然而,其他一些语言似乎有解决这个问题的机制:

  1. 一些函数式语言,例如 Haskell,可以定义类型级别的自然数。如果这在 C# 中是可能的,那么也应该可以定义

    Matrix<M, N>
    ,其中
    M
    N
    是类型级别的自然数。我对 F# 不太了解,但这个答案似乎表明这在 F# 中也是可能的。

  2. 在 C++ 中,可以使用带有非类型模板参数的模板。如果我理解正确的话,代码中实际使用的特定大小的类会在编译时生成。

现在,由于 C# 和 F# 都是 .NET 语言,我主要对上面的第 1 点感兴趣。是否可以在 F# 中实现我需要的类型,然后将它们作为库提供给我的应用程序?最好的情况是我可以在 F# 中仅定义类型级别的自然数,然后在 C# 中使用它们来定义

Matrix<M, N>

c# generics types f# language-design
1个回答
0
投票

我会使用带有静态成员的接口来完成此操作。在 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]);
© www.soinside.com 2019 - 2024. All rights reserved.