In einer Antwort auf diese Frage (geschrieben von Pete) gibt es einige Überlegungen zu OOP im Vergleich zu FP. Insbesondere wird vorgeschlagen, dass FP-Sprachen nicht sehr gut zum Modellieren von (persistenten) Objekten geeignet sind, die eine Identität und einen veränderlichen Zustand haben.
Ich habe mich gefragt, ob dies wahr ist oder mit anderen Worten, wie man Objekte in einer funktionalen Programmiersprache modellieren würde. Aufgrund meiner Grundkenntnisse in Haskell dachte ich, man könnte Monaden auf irgendeine Weise verwenden, aber ich weiß wirklich nicht genug über dieses Thema, um eine klare Antwort zu finden.
Wie werden Entitäten mit einer Identität und einem veränderlichen persistenten Zustand normalerweise in einer funktionalen Sprache modelliert?
Hier sind einige weitere Details, um zu verdeutlichen, was ich vorhabe. Nehmen Sie eine typische Java-Anwendung, in der ich (1) einen Datensatz aus einer Datenbanktabelle in ein Java-Objekt einlesen kann, (2) das Objekt auf verschiedene Arten ändern kann, (3) das geänderte Objekt in der Datenbank speichern kann.
Wie würde dies zB in Haskell umgesetzt? Ich würde den Datensatz zunächst in einen Datensatzwert einlesen (definiert durch eine Datendefinition), verschiedene Transformationen durchführen, indem ich Funktionen auf diesen Anfangswert anwende (jeder Zwischenwert ist eine neue, modifizierte Kopie des ursprünglichen Datensatzes) und dann den endgültigen Datensatzwert schreiben in die Datenbank.
Ist das alles was dazu gehört? Wie kann ich sicherstellen, dass zu jedem Zeitpunkt nur eine Kopie des Datensatzes gültig / zugänglich ist? Man möchte nicht, dass unterschiedliche unveränderliche Werte unterschiedliche Schnappschüsse desselben Objekts darstellen, um gleichzeitig zugänglich zu sein.
Antworten:
Der übliche Weg, um Zustandsänderungen in einer reinen Sprache wie Haskell vorzunehmen, besteht darin, sie als Funktionen zu modellieren, die den alten Zustand annehmen und eine modifizierte Version zurückgeben. Selbst bei komplexen Objekten ist dies aufgrund der verzögerten Bewertungsstrategie von Haskell effizient. Obwohl Sie ein neues Objekt syntaktisch erstellen, wird es nicht vollständig kopiert. Jedes Feld wird nur ausgewertet, wenn es benötigt wird.
Wenn Sie mehr als ein paar lokale Zustandsänderungen haben, können die Dinge ungeschickt werden. Hier kommen Monaden ins Spiel. Das Monadenparadigma kann verwendet werden, um einen Zustand und seine Änderungen zu kapseln. Das Lehrbuchbeispiel ist die
State
Monade, die mit einer Standardinstallation von Haskell geliefert wird. Beachten Sie jedoch, dass eine Monade nichts Besonderes ist: Es handelt sich lediglich um einen Datentyp, der zwei Methoden (>>=
undreturn
) verfügbar macht und einige Erwartungen erfüllt (die „Monadengesetze“). Unter der Haube macht die Staatsmonade genau das Gleiche: Nehmen Sie den alten Staat und geben Sie einen modifizierten Zustand zurück; Nur die Syntax ist besser.quelle
Ich bin kein Entwickler von funktionalen Sprachen, also schießen Sie mich bitte in Flammen ab, wenn ich das falsch habe, aber wenn es richtig ist, könnte es eine interessante Analogie sein.
Mir wurde einmal gesagt, dass Excel im Wesentlichen eine funktionale Sprache ist. Ich spreche nicht über VBA und so weiter, ich spreche darüber, was auf dem Blatt passiert.
Sie haben also Eingaben, die tabellarisch, einzelne Zellen oder benannte Bereiche usw. sein können, und über eine Kette von Operationen erhalten Sie ein Ergebnis oder viele Ergebnisse. Ändern Sie einen Eingang und es fließt sofort durch.
Hält diese Analogie Wasser?
quelle
Ich gehe davon aus, dass Sie über die staatenlose Eigenschaft einer reinen funktionalen Sprache sprechen.
Sie nehmen den Anfangszustand als Eingabe, Sie geben den Endzustand als Ausgabe zurück. Nichts unterscheidet sich grundlegend von dem, was Sie in einer Sprache mit einem Staatsbegriff tun, außer dass Sie expliziter darüber sind und dies langwierig und weniger effizient sein kann (*).
Beachten Sie, dass Sie nicht unbedingt alle Stellen ändern müssen, die auf Ihr Objekt verweisen: Sie können ein Token enthalten, und dann müssen Sie nur die Datenstruktur ändern, die die Token ihrem aktuellen Status zuordnet. Bis dahin implementieren Sie ein staatliches System in einer zustandslosen Sprache und erhalten die Probleme staatlicher Sprachen zurück.
(*) Zum Beispiel habe ich nach der Datenstruktur gesucht und diese nicht gefunden, die es mir ermöglicht, in O (1) eine modifizierte Kopie einer Datenstruktur zurückzugeben, die auch in O (1) durch aufeinanderfolgende ganze Zahlen indizierbar ist.
quelle
[(Int, v)]
können Sie den Wert an jedem Index in konstanter Zeit ersetzen, indem Sie einfach den neuen Wert berücksichtigen. Nachteile: Der alte Wert belegt immer noch RAM und die Suche ist linear.Kurz gesagt, jeder Status einer Entität ist eine eigene Entität. In Ihrer klassischen Geschäftslogik "Bestellen" gibt es also eine
Order
Entität und eineOrderVersion
Entität. Beide sind unveränderlich. Eine Logik, die eine Werbebuchung hinzufügt, verwendet die alte und eine neue VersionOrderLineItemVersion
als Eingabe und gibt eine neueOrderVersion
Entität zurück.Es macht einige Dinge einfacher (insbesondere "Rückgängig" -Funktionalität), aber einige Dinge sind schwieriger.
quelle