编译时未解析类型的 F# 类型错误

F# type error with unresolved type at compile time

我正在尝试一个实验,我正在包装一些数组以确保索引上的单位。我在此处的最后一行代码中遇到编译器错误。这是说类型参数 'Value' 不能使用,因为类型参数无法在编译时解析。我无法弄清楚为什么这会导致错误。我还尝试更改方法签名以限制 'Value 在两个数组中相同。

type ImArr<[<Measure>] 'Index, 'Value>(values: array<'Value>) =
    // We want to make sure we have our own copy to protect against mutation
    let values = values |> Array.copy

    member internal _.Values = values

    member this.Item
        with get(index: int<'Index>) =
            values.[int index]


type Arr<[<Measure>] 'Index, 'Value>(values: array<'Value>) =
    // We want to make sure we have our own copy to protect against mutation
    let values = values |> Array.copy

    member internal _.Values = values

    member inline _.Add (x: ImArr<'Index,_>) =
        if values.Length <> x.Values.Length then
            invalidArg (nameof x) "Cannot add arrays of different lengths"

        for idx = 0 to values.Length - 1 do
            values.[idx] <- values.[idx] + x.Values.[idx] // Error on this line

我试过的另一个方法签名也引发了错误。

member inline _.Add (x: ImArr<'Index,_>) =

错误消息图片:

我也尝试将工作提取到一个单独的函数中并得到了相同的结果。

type ImArr<[<Measure>] 'Index, 'Value>(values: array<'Value>) =
    // We want to make sure we have our own copy to protect against mutation
    let values = values |> Array.copy

    member internal _.Values= values

    member this.Item
        with get(index: int<'Index>) =
            values.[int index]


type Arr<[<Measure>] 'Index, 'Value>(values: array<'Value>) =
    // We want to make sure we have our own copy to protect against mutation
    let values = values |> Array.copy

    member this.Item
        with get(index: int<'Index>) =
            values.[int index]

        and set(index: int<'Index>) (value: 'Value) =
            values.[int index] <- value

    member internal _.Values = values


module Helpers =

    let inPlaceAdd<[<Measure>] 'Index, 'Value> (a: Arr<'Index, 'Value>) (b: ImArr<'Index, 'Value>) =
        let mutable i = 0;
        while i < a.Values.Length && i < b.Values.Length do
            a.Values.[i] <- a.Values.[i] + b.Values.[i] // ERROR
            i <- i + 1

并且编译错误

              a.Values.[i] <- a.Values.[i] + b.Values.[i]
  ----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^

stdin(31,29): error FS0001: The declared type parameter 'Value' cannot be used here since the type parameter cannot be resolved at compile time

我认为这里的主要问题是编译器不知道如何将两个泛型 'Value 相加。由于编译器无法推断如何执行此操作,您可能需要通过 statically resolved type parameters (SRTP) 给它一个提示,不幸的是,这在 F# 中非常不稳定。通过反复试验,我想出了一个版本的你的辅助函数,它编译时有一个警告但似乎可以工作:

let inline internal inPlaceAdd<[<Measure>] 'Index, ^Value when ^Value : (static member (+) : ^Value * ^Value -> ^Value)> (a: Arr<'Index, 'Value>) (b: ImArr<'Index, 'Value>) =
    let mutable i = 0;
    while i < a.Values.Length && i < b.Values.Length do
        let x = (^Value : (static member (+) : ^Value * ^Value -> ^Value)(a.Values.[i], b.Values.[i]))
        a.Values.[i] <- x
        i <- i + 1

请注意极其复杂的加法调用,它会导致编译器警告 FS0077: Member constraints with the name 'op_Addition' are given special status by the F# compiler...。当然,您应该能够直接添加值,如下所示:

let x = a.Values.[i] + b.Values.[i]

但由于某种原因,它无法编译:A type parameter is missing a constraint 'when ( ^Value or ^?11121) : (static member ( + ) : ^Value * ^?11121 -> ^?11122)' 这对我来说似乎是一个编译器错误,但谁知道呢。

用法:

let a = Arr([|1; 2; 3|])
let b = ImArr([|2; 3; 4|])
Helpers.inPlaceAdd a b
printfn "%A" a.Values   // [|3; 5; 7|]

这是 F# 编译器的一个已知问题:最好让 F# 编译器推断约束而不是手动编写约束。

这是一个允许 F# 编译器推断它的解决方案:

module Helpers =

    let inline inPlaceAdd<[<Measure>] 'Index, .. > (a: Arr<'Index, 'Value>) (b: ImArr<'Index, 'Value>) : unit =
        let mutable i = 0;
        while i < a.Values.Length && i < b.Values.Length do
            a.Values.[i] <- a.Values.[i] + b.Values.[i] // ERROR
            i <- i + 1

写起来更容易,而且不会产生任何警告。