F# - 如何使用get_Zero扩展类型,以便我可以使用现有类型?

Ove*_*urg 6 .net f# complex-numbers

我尝试以下方法:

let c x = System.Numerics.Complex(x, 0.0)
let sum = [c 1.0; c 2.0] |> List.sum
Run Code Online (Sandbox Code Playgroud)

但我得到这个错误:

The type 'System.Numerics.Complex' does not support the operator 'get_Zero'

我从https://msdn.microsoft.com/en-us/library/dd233211.aspx上阅读了类型扩展的规则,并尝试执行以下操作:

module ComplexExtension =
    let c x = System.Numerics.Complex(x, 0.0)

    type System.Numerics.Complex with
        // I also tried a bunch of other ways of writing these
        // as static or instance members, but nothing worked
        static member Zero = c 0.0
        static member One = c 1.0

open ComplexExtension

let sum = [c 1.0; c 2.0] |> List.sum
Run Code Online (Sandbox Code Playgroud)

我仍然得到那个错误.

是否可以使用get_Zero运算符扩展类型?或者我是否必须创建自己的包装类型System.Numerics.Complex并覆盖所有运算符,如果我希望它执行复杂数字的其他操作?

Gus*_*Gus 5

List.sum使用静态成员约束。静态成员约束不考虑扩展方法,因此这不是一个选项。

包装整个复杂类型是一种选择,但它是矫枉过正的,如果它只是一个特定的调用,您有很多方法可以通过多次击键来计算总和,您可以使用 a fold,如另一个答案所示。或者,List.reduce (+)如果您确定列表将始终至少包含一个元素,则可以使用。

这可能会在未来版本的 F# 中得到修复,但问题是静态成员约束不适用于字段,除非它们有 getter。但是,在 F# 库中,他们可以“模拟”现有类型的那些成员,他们通常使用原始类型来执行此操作,否则将无法与int, 一起使用float,因为它们也没有该成员。

我不确定Complex中定义的事实是否是System.Numerics不以这种方式实现它的原因,或者他们可能只是忘记了它。在任何情况下,您都可以打开问题或提交拉取请求以修复它。

最后,如果您仍想以通用方式使用它,另一种选择是重新定义sum函数。例如,来自最新F#+版本的sum函数(这里是源代码)可以正常工作(它有同样的问题,但很容易修复,实际上它是一个错误)几乎所有数字类型,包括大多数第三方数字类型,因为它具有回退机制,当类型没有成员时,该机制依赖于某些转换。Complexget_Zero