2010-05-11 7 views
10

Ich möchte den (/) Operator in F # für Strings überladen und die Bedeutung für Zahlen beibehalten.Überladungsoperator in F #: (/)

/// Combines to path strings 
let (/) path1 path2 = Path.Combine(path1,path2) 

let x = 3/4 // doesn't compile 

Wenn ich folgendes versuchen erhalte ich „Warning 29 Verlängerungs-Mitglieder können nicht Betreiber Überlastungen sorgen. Betrachten wir die Betreiber im Rahmen der Typdefinition definieren, statt.“

/// Combines to path strings 
type System.String with 
    static member (/) (path1,path2) = Path.Combine(path1,path2) 

Irgendwelche Ideen?

Grüße, forki

+0

Haben Sie versucht, es als op_Division definieren? UPDATE: macht nichts; Es wird nicht funktionieren – pblasucci

+0

Ich glaube nicht, dass Sie Mitglieder (oder Operatoren) über bereits vorhandene Klassen überladen können. – Gabe

Antwort

18

Sie nicht überladene Operatoren für bestehende Typen zur Verfügung stellen kann. Eine Option ist die Verwendung eines anderen Benutzernamens (wie von Natahan vorgeschlagen). Sie können jedoch auch einen neuen Typ darstellen Pfade in Ihrer F # Code definieren und die / Betreiber für diese Art bieten:

open System  

// Simple type for representing paths 
type Path(p) = 
    // Returns the path as a string 
    member x.Path = p 
    // Combines two paths 
    static member (/)(p1:Path, p2:Path) = 
    Path(IO.Path.Combine(p1.Path, p2.Path)) 

let n = 4/2 
let p = Path("C:\\")/Path("Temp") 

Dies hat einen wichtigen Vorteil - durch die Typen deutlicher zu machen, können Sie die Typprüfer geben Weitere Informationen, mit denen Sie Ihren Code überprüfen können. Wenn Sie Zeichenfolgen zum Darstellen von Pfaden verwenden, können Sie den Pfad leicht mit einer anderen Zeichenfolge verwechseln (z. B. Name). Wenn Sie Ihren Typ Path definieren, verhindert der Typ-Checker, dass Sie diesen Fehler machen.

Darüber hinaus wird der Compiler ermöglicht es Ihnen nicht (einfach) kombinieren Pfade falsch (was leicht passieren kann, wenn Sie Pfade als Strings darstellen), weil p + p nicht definiert ist (nur / verwenden können, die Path.Combine korrekt verwendet) .

+2

Es ist schön, wenn eine Person, die ein Buch zu diesem Thema geschrieben hat, eine Frage beantwortet! –

+1

Hrm, was ist mit Syntax in diesen Zeilen: (Lassen Sie p = Pfad "C: \\"/"Temp") durch Bereitstellung eines p1: Pfad, P2: String-Überladung? –

5

Ich glaube nicht, dies in F # möglich ist, basierend auf einer Lesung von the overloading documentation.

Ich würde stattdessen vorschlagen, dass Sie Ihre eigene Funktion erstellen, die wie/ aussieht, ist aber nicht. Etwas wie:

let (</>) path1 path2 = Path.Combine (path1,path2) 

Dies ist wahrscheinlich weniger störend auf langer Sicht sein, weil es nicht Chaos mit der impliziten Typinferenz, dass der menschliche Leser ist running-- / bedeutet, dass das Ergebnis eine Gleitkomma ist, und daran zu erinnern, dass es manchmal eine Schnur ist, ist eine Last *. Aber nach dem ersten Mal sieht der Leser </>, es ist leicht zu erinnern, dass es etwas mit dem Symbol in der Mitte eingebettet tut.

* Ich denke, der einzige Grund, + für Streicher sieht OK ist Überbelichtung. Nach der Verwendung von Haskell oder Caml für eine lange Zeit, die ersten paar Minuten nach dem Wechsel zu einer anderen Sprache macht "foo" + "bar" aussehen schrill schlecht.

+0

Ich benutze (@@) im Moment, aber ich denke (/) wäre schöner. – forki23

8

Ich glaube nicht, dass es eine direkte Möglichkeit gibt, das zu tun. Erweiterung Mitglieder werden nicht berücksichtigt für Operator überladen in F #, und es gibt keine gute Möglichkeit, die Operation in einer semi-generischen Art und Weise mit Member Einschränkungen neu zu definieren.

Es ist möglich, etwas zusammen zu hacken, die funktioniert, aber es ist sehr hässlich:

type DivisionOperations = 
    static member Divide(x:int, y:int) = x/y 
    static member Divide(path1, path2) = Path.Combine(path1, path2) 

let inline div< ^t, ^a, ^b, ^c when (^t or ^a) : (static member Divide : ^a * ^b -> ^c)> a b = ((^t or ^a) : (static member Divide : ^a * ^b -> ^c) (a, b)) 

let inline (/) x y = div<DivisionOperations, _, _, _> x y 
8

Eigentlich können Sie.

Try this:

open System.IO 

type DivExtension = DivExtension with 
    static member inline (=>) (x    , DivExtension) = fun y -> x/y 
    static member  (=>) (x    , DivExtension) = fun y -> Path.Combine(x, y) 
    static member  (=>) (x:DivExtension, DivExtension) = fun DivExtension -> x 

let inline (/) x y = (x => DivExtension) y 
+2

Beachten Sie, dass das meiner Antwort ziemlich ähnlich ist, obwohl Sie die Dummy DivExtension DivExtestion DivExtension DivExtension verwenden konnten, um die erste Überladung zu verallgemeinern und gleichzeitig zu verhindern, dass der Compiler den '(/) 'Betreiber auf die zweite Überladung, die sehr schlau ist. Ich fühle, dass die Verwendung des '(=>)' symbolischen Operators den Körper von '(/)' schwerer verständlich macht, obwohl Sie die expliziten statischen Element-Constraints weglassen können. – kvb

+0

Ja, du hast Recht. Ich bevorzuge die Verwendung von Zwischenoperatoren, um das Schreiben der statischen Beschränkungen zu vermeiden. In Ihrer Antwort können Sie auch die Dummy-Überladung hinzufügen, und es wird auch verallgemeinern. Eine Sache, die ich ohne Operatoren nicht machen kann, ist zweimal das 'oder' zu schreiben, ich meine etwas wie wenn (^ t oder^a oder^b). In diesen Fällen benutze ich den ternären Operator, ich denke es ist der einzige Weg. – Gustavo

+0

Hallo, ich habe getestet und es funktioniert, aber ich verstehe wirklich nicht warum (ich bin neu in F #) ... – Liviu