F#过于激进的类型推断?

时间:2012-09-24 20:32:38

标签: f# pattern-matching type-inference

因此,在执行一些Project Euler问题时,我希望能够取整数值的平方根(int,long,bigint等),但Sqrt仅定义为浮点值。所以我一直在编写我自己的小Newton-Raphson算法,它对于我需要的东西来说非常准确。但是,我希望能够在浮点值上调用内置的sqrt函数。所以我写了这样的话:

let inline dsqrt x =
    match box x with
    | :? float -> sqrt x
    | :? float32 -> sqrt x
    | _ -> p_dsqrt x

显然,我的功能名为“p_dsqrt”。但是,此函数要求输入定义了Sqrt方法,这种方法会破坏整个目的。我错过了一些类型约束,还是什么?

2 个答案:

答案 0 :(得分:6)

如果您想使用匹配,则不需要inline关键字,但如果您想使用内联函数和"帽子类型",请使用重载而不是匹配:

type Sqrt = Sqrt with
    // Dummy overload in order to get the right types inferred (will never reach here)
    static member inline ($) (Sqrt, _:^t when ^t:null and ^t: struct) = id

    // Existing sqrt
    static member inline ($) (Sqrt, x:'a) :'a = sqrt x 

    // Your Newton-Raphson based sqrt's
    static member        ($) (Sqrt, x:int   ) = sqrtForInt    x
    static member        ($) (Sqrt, x:bigint) = sqrtForBigInt x 

let inline sqrt (x:'t) :'t = Sqrt $ x 

返回类型将始终与输入类型相同,并且所选sqrt的实现将取决于该类型。此选择将在编译时发生,这是与在运行时解析的匹配方法的主要区别。

如果我取出虚拟重载,它将遇到与代码相同的问题:它将需要sqrt约束。

答案 1 :(得分:3)

我想你可能想要这个,而不是:

let dsqrt x =
    match box x with
    | :? float as f -> sqrt f |> box :?> 'a
    | :? float32 as f -> sqrt f |> box :?> 'a
    | _ -> p_dsqrt x

您的代码存在的问题是您直接调用sqrt x,这会限制x的可能类型。在我修改过的代码中,我将新标识符绑定到成功强制的结果为floatfloat32,因此这不会对x的类型施加任何约束。