【问题标题】: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?为什么内联函数的类型推断会强制参数为某种类型,而不是将其限制为具有 op_Explicit?
【发布时间】:2016-09-19 17:17:59
【问题描述】:

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,即使我明确要求 转换为浮点数。我错过了什么,或者更好的是,我怎样才能恢复 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 可区分联合,它会正确推断第一个参数的类型,因为 “需要成员 op_Explicit”

【问题讨论】:

    标签: generics f# constraints type-inference


    【解决方案1】:

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

    既然“失败”只适用于x,而不适用于y,那么让我们看看:xy有何不同?

    答案在最后一行:x 用于构造XTest&lt;'T&gt; 的实例。但是T 是什么?嗯,很明显,'TDivide 的返回类型的泛型参数,但是那个返回类型是什么?

    那个的答案在倒数第四行:XTest.Value res。由于resfloat(两个floats相除的结果),这意味着Divide的返回类型必须是XTest&lt;float&gt; option,这反过来意味着最后一行也必须产生XTest&lt;float&gt; ,这意味着x 必须是float

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

    【讨论】:

    • 谢谢,一如既往的出色回答:)。它也隐含地显示了解决方案。我只需要让类型推断知道x 不属于float 类型,我通过将最后一行更改为Some (XTest.Other (float x)) 来做到这一点。
    猜你喜欢
    • 2016-01-08
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 2012-08-09
    • 1970-01-01
    • 1970-01-01
    • 2021-11-23
    • 1970-01-01
    相关资源
    最近更新 更多