Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# - How do I extend a type with get_Zero so I can use an existing type generically?

I attempt the following:

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

But I get this error:

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

I read the rules on type extensions, from https://msdn.microsoft.com/en-us/library/dd233211.aspx, and try to do the following:

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

I still get that error.

Is it possible to extend a type with the get_Zero operator? Or do I have to create my own wrapper type around System.Numerics.Complex and override all the operators if I want it to do the other things that complex numbers do?

like image 292
Overlord Zurg Avatar asked Oct 28 '15 23:10

Overlord Zurg


2 Answers

List.sum uses static member constraints. Static member constraints don't look into extensions methods so that's not an option.

Wrapping the whole complex type is an option but it's overkill, if it is just a specific call you have many ways to compute the sum with a few more keystrokes, you can use a fold as shown on the other answer. Alternatively you can use List.reduce (+) if you are sure that the list will always have at least one element.

This might be possible to get fixed in a future version of F# but the problem is that static member constraints don't work with fields, unless they have a getter. However in the F# lib they can "emulate" those members for existing types, they do it normally with primitive types otherwise it wouldn't work with int, float, since they don't have that member either.

I'm not sure if the fact that Complex is defined in System.Numerics was the reason not to implement it this way, or may be they just forgot it. In any case you can open an issue or submit a pull request to get it fixed.

Finally another option if you still want to use it in a generic way is to redefine the sum function. For instance the sum function (here's the source) from the latest F#+ version will work fine (it had the same problem but was very easy to fix, actually it was a bug) with practically all numeric types, including Complex and most third party numeric types because it has a fallback mechanism which relies in some conversions when the type doesn't have a get_Zero member.

like image 189
Gus Avatar answered Oct 23 '22 04:10

Gus


List.sum doesn't recognize a Zero defined as extension. It must be part of the type.

Use List.fold instead:

let sum = [c 1.0; c 2.0] |> List.fold (+) Complex.Zero

BTW System.Numerics.Complex actually has a static Zero, but it's a field, not a property.

like image 2
Jakub Lortz Avatar answered Oct 23 '22 04:10

Jakub Lortz