2016-09-19 48 views
1

一个非常方便的功能是,你可以做内联和保值型的多态性一定程度的(虽然我认为“鸭打字”更贴切):为什么内联函数的类型推断强迫参数为某种类型,而不是将其限制为具有op_Explicit?在F#

// 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“

回答

10

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

由于“失败”只适用于x,但不y,让我们来看看:如何从yx不同?

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

的答案位于底部的第四行:XTest.Value res。由于resfloat(分割2个float S的结果),则这意味着Divide的返回类型必须是XTest<float> option,这反过来又意味着,最后一行也必须产生XTest<float>,这意味着x必须是float

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

+2

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

相关问题