You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在C#中定义MatrixMxN无限类族的实现方案探讨

编译时矩阵维度校验的实现方案

C# 中的模拟实现

C# 本身没有原生的类型级自然数支持,但可以通过标记类型+泛型约束+代码生成的组合方式模拟实现编译时维度校验,核心思路是用空结构体标记维度,通过泛型参数约束矩阵乘法的维度匹配规则。

1. 标记维度的基础实现

首先定义表示维度的空结构体,然后基于泛型定义矩阵类和类型安全的乘法方法:

// 定义维度标记类型(可手动定义常用维度,或用代码生成器批量生成)
public struct D1 { }
public struct D2 { }
public struct D3 { }
public struct D4 { }

public class Matrix<Rows, Cols>
{
    private readonly double[,] _data;

    public Matrix(double[,] data)
    {
        // 运行时兜底校验(防止手动传入错误维度的数据)
        if (data.GetLength(0) != GetDimension<Rows>() || data.GetLength(1) != GetDimension<Cols>())
            throw new ArgumentException("数据维度与类型标记不匹配");
        _data = data;
    }

    // 将标记类型映射为实际数值
    private static int GetDimension<T>()
    {
        return typeof(T) switch
        {
            Type t when t == typeof(D1) => 1,
            Type t when t == typeof(D2) => 2,
            Type t when t == typeof(D3) => 3,
            Type t when t == typeof(D4) => 4,
            _ => throw new NotSupportedException("未定义的维度类型")
        };
    }

    // 类型安全的矩阵乘法:仅当A的列标记等于B的行标记时可调用
    public static Matrix<Rows, BCols> Multiply<ARows, ACols, BCols>(Matrix<ARows, ACols> a, Matrix<ACols, BCols> b)
    {
        int rows = GetDimension<ARows>();
        int cols = GetDimension<BCols>();
        int common = GetDimension<ACols>();
        double[,] result = new double[rows, cols];

        // 矩阵乘法计算逻辑
        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < cols; j++)
            {
                double sum = 0;
                for (int k = 0; k < common; k++)
                    sum += a._data[i, k] * b._data[k, j];
                result[i, j] = sum;
            }
        }

        return new Matrix<ARows, BCols>(result);
    }
}

使用时,若维度不匹配(比如Matrix<D2,D3>和Matrix<D2,D4>相乘),编译器会直接报错,达到编译时校验的目的。

2. 进阶:递归泛型模拟任意维度

如果需要支持任意自然数维度,可以用Peano数的递归泛型结构:

public struct Zero { }
public struct Succ<T> { }

public static class DimensionCalculator
{
    public static int GetValue<T>() => GetValueImpl<T>.Value;

    private static class GetValueImpl<T>
    {
        public static readonly int Value = typeof(T) switch
        {
            Type t when t == typeof(Zero) => 0,
            Type t when t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Succ<>) =>
                1 + GetValue(t.GetGenericArguments()[0]),
            _ => throw new NotSupportedException()
        };
    }
}

此时Matrix<Succ<Succ<Zero>>, Succ<Succ<Succ<Zero>>>>就代表2×3矩阵,但这种写法可读性较差,适合对维度灵活性要求极高的场景。

其他语言的原生实现

1. Rust(Const Generics)

Rust的稳定版支持常量泛型,可以直接用数值作为泛型参数,实现最直观的编译时维度校验:

use std::ops::Mul;

struct Matrix<const M: usize, const N: usize, T> {
    data: [[T; N]; M],
}

impl<const M: usize, const K: usize, const N: usize, T> Mul for Matrix<M, K, T>
where
    T: Copy + Default + std::ops::Add<Output = T> + std::ops::Mul<Output = T>,
{
    type Output = Matrix<M, N, T>;

    fn mul(self, rhs: Matrix<K, N, T>) -> Self::Output {
        let mut result = Matrix {
            data: [[T::default(); N]; M],
        };
        for i in 0..M {
            for j in 0..N {
                for k in 0..K {
                    result.data[i][j] += self.data[i][k] * rhs.data[k][j];
                }
            }
        }
        result
    }
}

使用时直接传入数值维度,维度不匹配会触发编译错误:

let a = Matrix { data: [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]] }; // 2×3矩阵
let b = Matrix { data: [[7.0], [8.0], [9.0]] }; // 3×1矩阵
let c = a * b; // 类型为Matrix<2, 1, f64>

2. Haskell(类型级自然数)

Haskell通过GHC扩展支持完整的类型级编程,用DataKinds和TypeLits可以轻松实现:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}

import GHC.TypeLits (Nat, KnownNat, natVal)
import Data.Array (Array, Ix, listArray, bounds)

newtype Matrix (m :: Nat) (n :: Nat) a = Matrix (Array (Int, Int) a)

-- 类型约束:m×k 矩阵 × k×n 矩阵 → m×n 矩阵
multiply :: (KnownNat m, KnownNat k, KnownNat n, Num a) => Matrix m k a -> Matrix k n a -> Matrix m n a
multiply (Matrix a) (Matrix b) = Matrix $ listArray ((0,0), (m-1, n-1)) 
    [sum [a!(i, l) * b!(l, j) | l <- [0..k-1]] | i <- [0..m-1], j <- [0..n-1]]
  where
    m = fromIntegral $ natVal (Proxy :: Proxy m)
    k = fromIntegral $ natVal (Proxy :: Proxy k)
    n = fromIntegral $ natVal (Proxy :: Proxy n)

3. F#(静态解析类型参数)

F#结合类型提供者和静态解析参数,兼顾函数式特性与.NET生态:

// 定义类型级自然数
type Zero = Zero
type Succ<'n> = Succ of 'n

// 简化维度别名
type D2 = Succ<Succ<Zero>>
type D3 = Succ<Succ<Succ<Zero>>>
type D1 = Succ<Zero>

type Matrix<'rows, 'cols>(data: float[,]) =
    member _.Data = data

// 类型约束:仅当A的列类型等于B的行类型时可调用
let multiply (a: Matrix<'r, 'c>) (b: Matrix<'c, 's>) =
    let rows = Array2D.length1 a.Data
    let cols = Array2D.length2 b.Data
    let common = Array2D.length2 a.Data
    let result = Array2D.zeroCreate rows cols
    for i in 0..rows-1 do
        for j in 0..cols-1 do
            result[i,j] <- [0..common-1] |> List.sumBy (fun k -> a.Data[i,k] * b.Data[k,j])
    Matrix<'r, 's>(result)

内容的提问来源于stack exchange,提问作者ummg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 14:04:50