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

Abe*_*bel 1 generics f# type-inference constraints

F#中一个非常方便的功能是你可以进行内联并保持一定级别的值类型多态(虽然我认为"duck-typing"更合适):

// can be used with any argument that implements op_Explicit: ^a -> float
let inline Divide a b = float a / float b
Run Code Online (Sandbox Code Playgroud)

但是当我将它扩展为包含在某个类型中时,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)
Run Code Online (Sandbox Code Playgroud)

也许需要注意的重要事项是:如果我删除了有Other区别的联合,它会将第一个参数的类型正确地推断为"要求成员op_Explicit"

Fyo*_*kin 10

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

由于"失败"只适用于x,但不是y,让我们看看:有什么x不同y

答案是在最后一行:x用于构造一个实例XTest<'T>.但是什么T呢?嗯,显然,'TDivide返回类型的泛型参数,但是返回类型是什么?

这个问题的答案是从底部起的第四行:XTest.Value res.因为resfloat(float除了两个s的结果),这意味着Divide返回类型必须是XTest<float> option,这反过来意味着最后一行也必须产生XTest<float>,这意味着x必须float.

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

  • 谢谢,优秀的答案,一如既往:).它也隐含地显示了解决方案.我只需要让类型推断知道`x`不知道是`float`类型,我通过将最后一行改为`Some(XTest.Other(float x))`来做. (2认同)