2015-10-28 10 views
5

Ich versuche folgendes:F # - Wie erweitere ich einen Typ mit get_Zero, damit ich einen vorhandenen Typ generisch verwenden kann?

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

Aber ich bekomme diese Fehlermeldung:

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

ich die Regeln auf Typerweiterungen zu lesen, von https://msdn.microsoft.com/en-us/library/dd233211.aspx, und versuchen Sie Folgendes zu tun:

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 

Ich bekomme immer noch diesen Fehler.

Ist es möglich, einen Typ mit dem Operator get_Zero zu erweitern? Oder muss ich meinen eigenen Wrapper-Typ um System.Numerics.Complex erstellen und alle Operatoren überschreiben, wenn ich möchte, dass es die anderen Dinge tut, die komplexe Zahlen tun?

+0

Ja, wahrscheinlich Wrapper erstellen ist ein Weg zu gehen. Siehe hier: http://stackoverflow.com/questions/3223660/can-existing-types-be-extended-to-work-with-seq-sum-etc – Petr

+0

Das Ding, das Sie suchen, heißt "höher-kinded Polymorphismus ", und leider unterstützt F # es im Allgemeinen nicht. Hier ist eine Benutzer-Sprachanfrage, bitte stimme: http: //fslang.uservoice.com/forums/245727-f-sprache/vorschläge/5664242-simulieren-höher-kinded-polymorphismus –

Antwort

4

List.sum verwendet statische Elementeinschränkungen. Statische Member-Constraints suchen nicht nach Erweiterungsmethoden, daher ist dies keine Option.

Einpacken des gesamten komplexen Typs ist eine Option, aber es ist Overkill, wenn es nur einen bestimmten Anruf Sie haben viele Möglichkeiten, um die Summe mit ein paar mehr Tastenanschläge zu berechnen, können Sie eine fold wie auf der anderen Antwort gezeigt. Alternativ können Sie List.reduce (+) verwenden, wenn Sie sicher sind, dass die Liste immer mindestens ein Element enthält.

Dies ist möglicherweise in einer zukünftigen Version von F # behoben, aber das Problem besteht darin, dass statische Elementeinschränkungen nicht mit Feldern funktionieren, außer sie haben einen Getter. In der F # -Bibliothek können diese Elemente jedoch für vorhandene Typen "emuliert" werden, they do it normally with primitive types andernfalls würde es nicht mit int, float funktionieren, da sie dieses Element auch nicht haben.

Ich bin mir nicht sicher, ob die Tatsache, dass Complex in System.Numerics definiert ist, der Grund war, es nicht auf diese Weise zu implementieren, oder vielleicht haben sie es einfach vergessen. In jedem Fall können Sie ein Problem öffnen oder eine Pull-Anfrage senden, um es zu beheben.

Eine weitere Option, wenn Sie es immer noch in generischer Weise verwenden möchten, ist die Neudefinition der sum Funktion. Zum Beispiel die sum Funktion (hier ist die source) von der letzten F#+ Version funktioniert gut (es hatte das gleiche Problem, aber war sehr einfach zu beheben, eigentlich war es ein Fehler) mit praktisch allen numerischen Typen, einschließlich Complex und die meisten dritten Partei numerisch types, weil es einen Fallback-Mechanismus hat, der auf einige Konvertierungen angewiesen ist, wenn der Typ kein get_Zero Mitglied hat.

1

List.sum erkennt keine Zero als Erweiterung definiert. Es muss Teil des Typs sein.

Verwenden List.fold statt:

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

BTW System.Numerics.Complex hat tatsächlich eine statische Zero, aber es ist ein Feld, keine Eigenschaft.

Verwandte Themen