(FS0193,FS1113)带有静态解析的类型参数的F#向量类

chr*_*art 5 generics f# types

我正在尝试Vector< ^F>在F#中实现泛型类,^F矢量元素的基础字段类型在哪里?这意味着,^F可以是满足加,减,乘和负的任何事物。

一些示例用户代码如下所示:

    let v = Vector<int>([| 1; 2; 3 |])
    let w = Vector<int>([| 4; 5; 6 |])
    let sum = v + w
Run Code Online (Sandbox Code Playgroud)

所以在这里我用的类型int,它可能是任何一个满足基本的基本操作如上所述。使用.NET样式泛型时,我似乎可以使用某些版本,但是我也遇到了问题。由于无论如何我都想使用SRTP,因此我再次走了这条路:

    type Vector< ^F when ^F : (static member (~-): ^F -> ^F)
                     and ^F : (static member (+): ^F * ^F -> ^F)
                     and ^F : (static member (*): ^F * ^F -> ^F)
               >(_values: ^F[]) =
        let values: ^F [] = _values
        member inline this.Values = values

        member inline this.Dimension = Array.length values

        // Constructs a Vector using given initializer
        static member inline Init (n: int) (initializer: (int -> ^F)) =
            Vector< ^F>(Array.init n (fun i -> initializer (i + 1)))

        member inline this.Item with get (i: int) = values.[i - 1]

        // negate a vector
        static member inline ( ~- ) (a: Vector< ^F>) =
            Vector< ^F>.Init (Array.length a.Values) (fun i -> -a.[i])

        // sum of two vectors
        static member inline ( + ) (a: Vector< ^F>, b: Vector< ^F>): Vector< ^F> =
            Vector< ^F>.Init (Array.length a.Values) (fun i -> a.[i] + b.[i])

        // difference of two vectors
        static member inline ( - ) (a: Vector< ^F>, b: Vector< ^F>): Vector< ^F> =
            Vector< ^F>.Init (Array.length a.Values) (fun i -> a.[i] + (-b.[i]))

        // scale vector by scalar
        static member inline ( * ) (a: ^F, b: Vector< ^F>): Vector< ^F> =
            Vector< ^F>.Init (Array.length b.Values) (fun i -> a * b.[i])
Run Code Online (Sandbox Code Playgroud)

但是我遇到的错误是精疲力尽,例如:

  • FS0193(警告):(A type parameter is missing a constraint 'when ( ^F or ^?12844) : (static member ( + ) : ^F * ^?12844 -> ^F)'但也针对运算符-*
  • FS1113(错误):The value 'Values' was marked inline but its implementation makes use of an internal or private function which is not-基本上到处都是,并且正在报告每个成员属性,成员函数和静态成员函数。

(上面的代码是可复制粘贴的,易于复制)

我该如何解决构造诸如Vector之类的类型的问题,whos元素和操作都具有静态解析的类型参数(或泛型),且没有错误。

Phi*_*ter 6

SRTP错误非常难以诊断,并且它是内部生成的类型ID泄漏到用户空间中的错误。错误消息可能尚不清楚,但是静态成员不能满足所有约束。如果将运算符分解到一个单独的模块中,则类型推断可以照顾到所有约束的使用(从F#4.6开始):

type Vector< ^F when ^F : (static member (~-): ^F -> ^F)
                and ^F : (static member (+): ^F * ^F -> ^F)
                and ^F : (static member (*): ^F * ^F -> ^F)
           >(_values: ^F[]) =
    let values: ^F [] = _values

    member inline __.Values = values
    member inline __.Dimension = Array.length values

    // Constructs a Vector using given initializer
    static member inline Init (n: int) (initializer: (int -> ^F)) =
        Vector< ^F>(Array.init n (fun i -> initializer (i + 1)))

    member inline __.Item with get (i: int) = values.[i - 1]

[<AutoOpen>]
module VectorOps =
    let inline ( ~- ) (v: Vector< ^F>) =
        Vector< ^F>.Init (Array.length v.Values) (fun i -> -v.[i])

    let inline ( + ) (a: Vector< ^F>)  (b: Vector< ^F>) =
        Vector< ^F>.Init (Array.length a.Values) (fun i -> a.[i] + b.[i])

    let inline ( - ) (a: Vector< ^F>)  (b: Vector< ^F>) =
        Vector< ^F>.Init (Array.length a.Values) (fun i -> a.[i] - b.[i])

    let inline ( * ) (k: ^F)  (v: Vector< ^F>) =
        Vector< ^F>.Init (Array.length v.Values) (fun i -> k * v.[i])
Run Code Online (Sandbox Code Playgroud)

然后,您可以按预期使用它:

let v1 = Vector<int>([|1;2;3;4;5|])
let v2 = Vector<int>([|1;2;3;4;5|])

let negv1 = -v1
negv1.Values |> Array.iter (fun x -> printfn "%d " x)

let sum  = v1 + v2
sum.Values |> Array.iter (fun x -> printfn "%d " x)

let diff = sum - v2
diff.Values |> Array.iter (fun x -> printfn "%d " x)

let scaled = 3 * diff
scaled.Values |> Array.iter (fun x -> printfn "%d " x)
Run Code Online (Sandbox Code Playgroud)

不幸的是,这陷入了您遇到F#编译器讨厌的一面的境地。SRTP并不是真正为这种编程风格而设计的,尽管它确实可以工作,但是这种情况的缺乏意图确实会在怪癖和错误消息中泄漏出来。