F#/在COMPILE时验证数组长度的最简单方法

Kon*_*nov 2 f# type-providers

我有一些科学项目.那里有各种长度的矢量/方形矩阵.显然(例如)长度为2的向量不能添加到长度为3的向量中(依此类推).有几个.NET库,它们处理向量/矩阵.所有这些都有通用的载体/矩阵或者有一些非常特殊的载体/矩阵,它们不能满足需要.

大多数(如果不是全部)这些库可以从列表或数组创建向量.不幸的是,如果我错误地给出了一个错误长度的输入数组,那么我将得到一个错误长度的向量,然后一切都会在运行时爆炸!

我想知道是否有可能在编译时检查数组长度,以便得到编译错误,如果,让我们说,我尝试将5元素数组传递给长度为2"构造函数"的向量.毕竟,printfn几乎就是这样!

我想到了F#类型的提供商,但我不确定如何在这里应用它们.

非常感谢!

Jus*_*mer 5

感谢OP提出了一个有趣的问题.我的答案频率下降并不是因为不愿意提供帮助,而是因为有一些问题引起了我的兴趣.

我们在F#中没有依赖类型,而F#不支持带有数字类型参数的泛型(如C++).

但是,我们可以为不同的维度创建不同的类型Dim1,Dim2依此类推,并将它们作为类型参数提供.

这将允许我们有一个类型签名,apply它应用一个像这样的矩阵的向量:

let apply (m : Matrix<'R, 'C>) (v : Vector<'C>) : Vector<'R> = …
Run Code Online (Sandbox Code Playgroud)

除非矩阵的列与向量的长度匹配,否则代码将无法编译.此外; 结果向量的长度是列的行数.

一种方法是定义一个接口IDimension和一些表示不同维度的具体实现.

type IDimension =
  interface 
    abstract Size : int
  end

type Dim1 () = class interface IDimension with member x.Size = 1 end end
type Dim2 () = class interface IDimension with member x.Size = 2 end end
Run Code Online (Sandbox Code Playgroud)

然后可以像这样实现矢量和矩阵

type Vector<'Dim  when  'Dim :> IDimension 
                  and   'Dim : (new : unit -> 'Dim)
           > () =
  class
    let dim = new 'Dim()

    let vs  = Array.zeroCreate<float> dim.Size

    member x.Dim    = dim
    member x.Values = vs
  end

type Matrix<'RowDim, 'ColumnDim when  'RowDim :> IDimension 
                                and   'RowDim : (new : unit -> 'RowDim) 
                                and   'ColumnDim :> IDimension 
                                and   'ColumnDim : (new : unit -> 'ColumnDim)
           > () =
  class
    let rowDim    = new 'RowDim()
    let columnDim = new 'ColumnDim()

    let vs  = Array.zeroCreate<float> (rowDim.Size*columnDim.Size)

    member x.RowDim     = rowDim
    member x.ColumnDim  = columnDim
    member x.Values     = vs
  end
Run Code Online (Sandbox Code Playgroud)

最后,这允许我们编写如下代码:

let m76 = Matrix<Dim7, Dim6> ()
let v6  = Vector<Dim6> ()
let v7  = apply m76 v6 // Vector<Dim7>

// Doesn't compile because v7 has the wrong dimension
let vv = apply m76 v7
Run Code Online (Sandbox Code Playgroud)

如果你需要各种各样的维度(因为你有一个代数递增/递减向量/矩阵的维度),你可以使用一些教会数字的智能变体来支持它.

如果这个可用或不可用完全取决于读者我认为.

PS.

如果它们适用于比浮子更多的类型,也许也可以使用单位措施.