Wenn ich den funktionalen Ansatz der Definition eines Typs und der Beschreibung von Funktionen (im Gegensatz zu Instanzmethoden) verwende, die auf diesen Typ angewendet werden, wie soll ich meinen Code organisieren?F #: Best Practices zum Organisieren von Typen und Modulen
Ich gehe im Allgemeinen eine von drei Arten:
(1):
module MyType =
type MyType (x : int) =
member val X = x with get
let myFunction myType y = myType.X + y
(2):
type MyType (x : int) =
member val X = x with get
[<RequireQualifiedAccess>]
module MyTypeOps =
let myFunction myType y = myType.X + y
(3):
type MyType =
{
x : int
}
static member MyFunction myType y = myType.x + y
Pro von (1) ist, dass Funktionen in einem Modul definiert sind. Nachteile von (1) sind, dass der Typ auch in dem Modul definiert ist, was zu hässlicher MyType.MyType
Redundanz bei Instanziierung und der Unfähigkeit [<RequireQualifiedAccess>]
führt, wenn Sie open MyType
als Workaround für diese Redundanz zulassen wollen.
Vorteile von (2) sind in einem Modul definierte Funktionen und keine redundante module.type. Con ist, dass das Modul nicht den gleichen Namen wie der Typ haben kann.
Pro (3) ist, dass die Methoden statisch sind und keine module.type Redundanz. Nachteile sind, dass Sie einige Typen (z. B. Nicht-Methode-Werte und aktive Muster) unter dieser Methode nicht definieren können.
Normalerweise bevorzuge ich (2), obwohl ich es hasse, das Modul etwas zu nennen, das weniger beschreibend und intuitiv ist, als es sein sollte. (2) erlaubt mir auch gegenseitig abhängige Typen mit type ... and ...
in dem seltenen Fall zu erstellen, dass ich das tun muss, was offensichtlich für Typen nicht möglich ist, die in separaten Modulen wie Ansatz (1) definiert sind.
Welchen Ansatz nehmen meine anderen F # -Programmierer? Ich frage mich, ob ich etwas offensichtlich übersehen habe (oder nicht so offensichtlich), oder, wenn nicht, ob es da draußen eine Konvention gibt, die die Unfähigkeit adressiert, einem Modul den gleichen Namen wie seinem entsprechenden Typ zu geben der gleiche Namespace.
Die [Sammlungstypen in der F # Standardbibliothek] (https://github.com/Microsoft/visualfsharp/blob/master/src/fsharp/FSharp.Core/list.fs) folgen auch dem Modul mit dem gleichen Name als Typ 'Muster' (allerdings ohne die entsprechenden Methoden an den Typ angehängt zu haben). –
Interessante Wahl, mit diesem CompilationRepresentation Attribut (ich hatte das vorher nicht gesehen, danke für den Tipp). Ich gebe Ihnen das Häkchen für diese Antwort, da es eine großartige Antwort auf meine Frage ist, obwohl die C# Interoperabilität betroffen ist (was für mich ein Problem ist), es ist im Grunde das gleiche wie die zweite der drei Methoden, die ich aufgelistet habe . Plus, ich mag es nicht, Funktionalität in Member-Methoden zu programmieren; Ich bevorzuge das im entsprechenden Modul, da ich meine Typen gerne auf die Deklaration von Eigenschaften beschränke (und keine Funktionen an sie angehängt habe). – MiloDC
Nur aus Neugierde, wenn Warteschlange ein Datensatztyp ist, den Sie von C# idiomatisch machen möchten (da ich dazu tendiere, meine Funktionen von meinen Typen zu trennen, verwende ich Datensätze eine LOT), wie definieren Sie dann aktive Muster Mitglied Methoden? – MiloDC