为什么内联函数的类型推断会强制参数为某种类型,而不是将其限制为 op_Explicit?

Why is type inference for an inline function forcing an argument to be of a certain type, as opposed to restricting it to having op_Explicit?

F# 中一个非常方便的功能是您可以进行内联并保持一定程度的值类型多态性(尽管我认为 "duck-typing" 更合适):

// can be used with any argument that implements op_Explicit: ^a -> float
let inline Divide a b = float a / float b

但是当我将其扩展为包含在特定类型中时,F# 推断第一个参数为 float,即使我明确要求 转换为 float.我错过了什么,或者更好的是,我怎样才能恢复 op_Explicit 行为?我尝试添加静态成员约束,但这似乎没有帮助:

type XTest<'T> =
    | Value of 'T
    | Other of 'T 
    // a is inferred as float, b as req. op_Explicit
    static member inline Divide a b =
        match a with
        | Value x -> 
            match b with
            | Value y ->
                let res = float x / float y
                XTest.Value res |> Some
            | _ -> failwith "not implemented"

        | Other x-> Some (XTest.Other x)

可能需要注意:如果我删除 Other discriminated union,它会将第一个参数的类型正确推断为 "requires member op_Explicit"

这不是因为类型推断失败。事实上,如果仔细观察,您会发现 y 被正确推断为 'a (requires op_Explicit).

由于"failure"只适用于x,而不适用于y,让我们看看:xy有何不同?

答案在最后一行:x用于构造XTest<'T>的实例。但是 T 是什么?好吧,很明显,'TDivide 的 return 类型的通用参数,但是那个 return 类型是什么?

that 的答案在倒数第四行:XTest.Value res。由于 res 是一个 float(将两个 float 相除的结果),这意味着 Divide 的 return 类型必须是 XTest<float> option,这反过来意味着最后一行也必须产生 XTest<float>,这意味着 x 必须是 float.

类型推断的胜利。不是失败。 :-)