In vielen Jahren der OO-Programmierung habe ich verstanden, was diskriminierte Gewerkschaften sind, aber ich habe sie nie wirklich vermisst. Ich habe vor kurzem einige funktionale Programmierung in C # gemacht und jetzt stelle ich fest, dass ich mir immer wünsche, ich hätte sie. Das verwirrt mich, weil das Konzept der diskriminierten Gewerkschaften auf den ersten Blick völlig unabhängig von der funktionalen Dichotomie zu sein scheint.
Enthält die funktionale Programmierung etwas, das diskriminierte Gewerkschaften nützlicher macht als dies in OO der Fall wäre, oder ist es so, dass ich mich dazu gezwungen habe, das Problem "besser" zu analysieren, meine Standards einfach erhöht habe und nun ein besseres verlange Modell?
Antworten:
Diskriminierte Gewerkschaften glänzen wirklich in Verbindung mit der Mustererkennung, bei der Sie je nach Fall ein anderes Verhalten auswählen. Dieses Muster widerspricht jedoch grundsätzlich den reinen OO-Prinzipien.
In reinen OO sollten Verhaltensunterschiede durch die Typen (Objekte) selbst definiert und eingekapselt werden. Die Entsprechung zum Pattern Matching besteht also darin, eine einzelne Methode für das Objekt selbst aufzurufen, die dann von den fraglichen Subtypen überladen wird, um ein anderes Verhalten zu definieren. Das Untersuchen des Objekttyps von außen (wie bei der Mustererkennung) wird als Gegenmuster angesehen.
Der grundlegende Unterschied besteht darin, dass Daten und Verhalten bei der funktionalen Programmierung voneinander getrennt sind, während Daten und Verhalten in OO zusammengefasst sind.
Dies ist der historische Grund. Eine Sprache wie C # entwickelt sich von einer klassischen OO-Sprache zu einer Multi-Paradigma-Sprache, indem immer mehr Funktionsmerkmale integriert werden.
quelle
List<A>
die MethodeB Match<B>(B nil, Func<A,List<A>,B> cons)
. Dies ist beispielsweise genau das Muster, das Smalltalk für Boolesche Werte verwendet. So geht Scala im Grunde auch damit um. Die Verwendung mehrerer Klassen ist ein Implementierungsdetail, das nicht offengelegt werden muss.isEmpty
Methode, die prüft, ob der Verweis auf den nächsten Knoten null ist.Nachdem ich vor dem Erlernen der funktionalen Programmierung in Pascal und Ada programmiert habe, verbinde ich diskriminierte Gewerkschaften nicht mit funktionaler Programmierung.
Diskriminierte Gewerkschaften sind in gewisser Weise das doppelte Erbe. Die erste Option ermöglicht das einfache Hinzufügen von Vorgängen zu einer festen Gruppe von Typen (denjenigen in der Union), und die Vererbung ermöglicht das einfache Hinzufügen von Typen mit einer festen Gruppe von Vorgängen. (Das einfache Hinzufügen von beiden wird als Ausdrucksproblem bezeichnet. Dies ist ein besonders schwieriges Problem für Sprachen mit einem statischen Typsystem.)
Aufgrund der Betonung von OO auf Typen und der doppelten Betonung der funktionalen Programmierung auf Funktionen weisen funktionale Programmiersprachen eine natürliche Affinität zu Unionstypen auf und bieten syntaktische Strukturen, um deren Verwendung zu vereinfachen.
quelle
Imperative Programmiertechniken, wie sie in OO häufig verwendet werden, basieren häufig auf zwei Mustern:
null
, um "kein Wert" oder Fehler anzuzeigen.Das Funktionsparadigma vermeidet normalerweise beides und gibt vorzugsweise einen zusammengesetzten Typ zurück, der den Grund für Erfolg / Misserfolg oder den Wert / keinen Wert angibt.
Für diese zusammengesetzten Typen sind diskriminierte Gewerkschaften genau das Richtige. In der ersten Instanz könnten Sie beispielsweise
true
eine Datenstruktur zurückgeben, die den Fehler beschreibt. Im zweiten Fall, eine Vereinigung , die einen Wert enthält, odernone
,nil
etc. Der zweite Fall ist so verbreitet, dass viele funktionale Sprachen haben ein „vielleicht“ oder „Option“ Typ eingebaute in diesen Wert / keine Vereinigung zu vertreten.Wenn Sie beispielsweise mit C # zu einem funktionalen Stil wechseln, werden Sie schnell feststellen, dass diese zusammengesetzten Typen erforderlich sind.
void/throw
undnull
fühle mich einfach nicht richtig mit solchem Code. Und diskriminierte Gewerkschaften (DUs) sind genau das Richtige. Sie wollten sie, genau wie viele von uns.Die gute Nachricht ist, dass es viele Bibliotheken gibt, die DUs in z. B. C # modellieren (schauen Sie sich zum Beispiel meine eigene Succinc <T> -Bibliothek an).
quelle
Summentypen wären in den gängigen OO-Sprachen im Allgemeinen weniger nützlich, da sie eine ähnliche Art von Problem lösen wie die OO-Subtypisierung. Eine Möglichkeit, sie zu betrachten, besteht darin, dass beide Subtypen behandeln, aber OO ist, dass man
open
einem übergeordneten Typ beliebige Subtypen hinzufügen kann und dass Summentypen sind,closed
dh man bestimmt im Voraus, welche Subtypen gültig sind.Jetzt kombinieren viele OO-Sprachen die Untertypisierung mit anderen Konzepten wie geerbten Strukturen, Polymorphismus, Referenztypisierung usw., um sie allgemein nützlicher zu machen. Eine Konsequenz ist, dass sie in der Regel aufwändiger einzurichten sind (mit Klassen und Konstruktoren und so weiter) und daher eher nicht für Dinge wie
Result
s undOption
s usw. verwendet werden, bis die allgemeine Typisierung üblich wurde.Ich würde auch sagen, dass der Fokus auf reale Beziehungen, den die meisten Menschen zu Beginn der OO-Programmierung erlernten, z. Obwohl die Ideen ziemlich ähnlich sind.
Ein möglicher Grund dafür, warum funktionale Sprachen das geschlossene Schreiben dem offenen Schreiben vorziehen, ist, dass sie den Mustervergleich bevorzugen. Dies ist nützlich für den Funktionspolymorphismus, funktioniert aber auch sehr gut bei geschlossenen Typen, da der Compiler statisch überprüfen kann, ob der Abgleich alle Subtypen abdeckt. Dies kann dazu führen, dass sich die Sprache konsistenter anfühlt, obwohl ich nicht glaube, dass es einen inhärenten Vorteil gibt (ich könnte mich irren).
quelle
sealed
bedeutet "kann nur in derselben Kompilierungseinheit erweitert werden", wodurch Sie den Satz von Unterklassen zur Entwurfszeit schließen können.Swift verwendet gerne diskriminierende Gewerkschaften, außer es nennt sie "Enums". Enums sind eine der fünf grundlegenden Kategorien von Objekten in Swift, nämlich class, struct, enum, tuple und closure. Swift-Optionen sind Aufzählungen, bei denen es sich um diskriminierende Gewerkschaften handelt, und sie sind für jeden Swift-Code unbedingt erforderlich.
Die Prämisse, dass "diskriminierende Gewerkschaften mit funktionaler Programmierung verbunden sind", ist also falsch.
quelle