F# 过度攻击型推理?
因此,在处理一些问题时,我希望能够取整数值(int、long、bigint等)的平方根,但Sqrt仅为浮点值定义。所以我一直在写我自己的小牛顿-拉斐逊算法,它对于我所需要的非常精确。但是,我希望能够对浮点值调用内置的sqrt函数。所以我写了这样的东西:F# 过度攻击型推理?,f#,pattern-matching,type-inference,F#,Pattern Matching,Type Inference,因此,在处理一些问题时,我希望能够取整数值(int、long、bigint等)的平方根,但Sqrt仅为浮点值定义。所以我一直在写我自己的小牛顿-拉斐逊算法,它对于我所需要的非常精确。但是,我希望能够对浮点值调用内置的sqrt函数。所以我写了这样的东西: let inline dsqrt x = match box x with | :? float -> sqrt x | :? float32 -> sqrt x | _ -> p_dsqrt x
let inline dsqrt x =
match box x with
| :? float -> sqrt x
| :? float32 -> sqrt x
| _ -> p_dsqrt x
显然,我的函数名为“p_dsqrt”。然而,这个函数要求输入定义一个Sqrt方法,这有点违背了整个目的。我是否缺少某种类型约束,或者什么?我想您可能希望这样:
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
的可能类型。在我修改的代码中,我将一个新的标识符绑定到成功强制到float
或float32
的结果,因此这不会对x
的类型施加任何约束。如果要使用匹配,则不需要内联关键字,但如果要使用内联函数和“帽子类型”,使用重载而不是匹配:
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的实现将取决于该类型。此选择将发生在编译时,这是与在运行时解析的match方法的主要区别
如果我去掉伪重载,它将与您的代码有相同的问题:它将需要sqrt约束。如果它有用,下面是我在Euler问题中用于整数平方根的代码:预期的返回类型是什么?但是,
dsqrt
不应该仍然是内联的
,要正确地将x
的类型传播到p\u dsqrt
?不幸的是,我现在遇到了一个不同的错误。我得到“类型‘float’与类型‘float32’不匹配”。当我删除'float32'案例时,函数仍然解析为“float->float”。作为参考,我的p_dsqrt函数解析为“'a->'a”。@leecarbtree-对不起,我更新了我的答案。还需要动态转换回泛型类型。哇,这太棒了:)这是如何工作的?我看不懂我在读什么!但结果令人印象深刻。