Ich habe gelernt, wie man hauptsächlich vom OOP-Standpunkt aus programmiert (wie die meisten von uns, da bin ich mir sicher), aber ich habe viel Zeit damit verbracht, zu lernen, wie man Probleme auf funktionale Weise löst. Ich habe ein gutes Verständnis für die Lösung von Rechenproblemen mit FP, aber wenn es um kompliziertere Probleme geht, greife ich immer wieder auf veränderbare Objekte zurück. Wenn ich zum Beispiel einen Partikelsimulator schreibe, möchte ich, dass Partikel- "Objekte" mit einer veränderlichen Position aktualisiert werden. Wie werden inhärent "zustandsbehaftete" Probleme normalerweise mit funktionalen Programmiertechniken gelöst?
functional-programming
Andrew Martin
quelle
quelle
Antworten:
Funktionale Programme verarbeiten den Status sehr gut, erfordern jedoch eine andere Sichtweise. Für Ihr Positionsbeispiel ist zu berücksichtigen, dass Ihre Position eine Funktion der Zeit anstelle eines festen Werts ist . Dies funktioniert gut für Partikel, die einem festen mathematischen Pfad folgen. Sie benötigen jedoch eine andere Strategie, um mit einer Änderung des Pfads umzugehen, z. B. nach einer Kollision.
Die grundlegende Strategie besteht darin, Funktionen zu erstellen, die einen Zustand annehmen und den neuen Zustand zurückgeben . Ein Partikelsimulator wäre also eine Funktion, die eine
Set
Anzahl von Partikeln als Eingabe verwendet undSet
nach einem Zeitschritt eine neue Anzahl von Partikeln zurückgibt . Dann rufen Sie diese Funktion einfach wiederholt auf, wobei der Eingang auf das vorherige Ergebnis gesetzt ist.quelle
Wie von @KarlBielefeldt festgestellt, besteht der funktionale Ansatz für ein solches Problem darin, es als Rückgabe eines neuen Zustands von einem vorherigen Zustand zu betrachten. Die Funktionen selbst enthalten keine Informationen, sodass sie den Status m immer auf den Status n aktualisieren .
Ich denke, Sie finden dies ineffizient, weil Sie davon ausgehen, dass der vorherige Zustand im Speicher gehalten werden muss, während der neue Zustand berechnet wird. Beachten Sie, dass die Wahl zwischen dem Schreiben eines vollständig neuen Status oder dem erneuten Schreiben des alten Status ein Implementierungsdetail aus Sicht einer funktionalen Sprache ist.
Angenommen, ich habe eine Liste mit einer Million Ganzzahlen und möchte die zehnte um eine Einheit erhöhen. Es ist verschwenderisch, die gesamte Liste mit einer neuen Nummer an der zehnten Stelle zu kopieren. Dies ist jedoch nur die konzeptionelle Beschreibung der Operation für den Sprachkompilierer oder -interpreter. Dem Compiler oder Interpreter steht es frei, die erste Liste zu nehmen und nur die zehnte Position zu überschreiben.
Der Vorteil der Beschreibung des Vorgangs auf diese Weise besteht darin, dass der Compiler die Situation beurteilen kann, in der viele Threads dieselbe Liste an verschiedenen Positionen aktualisieren möchten. Wenn die Operation als "Gehe zu dieser Position und überschreibe, was du findest" beschrieben wird, ist es der Programmierer, nicht der Compiler, der dafür verantwortlich ist, sicherzustellen, dass Überschreibungen nicht kollidieren.
Nach alledem gibt es sogar in Haskell eine staatliche Monade , mit deren Hilfe Situationen modelliert werden können, in denen das "Beibehalten des Zustands" eine intuitivere Lösung für ein Problem darstellt. Beachten Sie jedoch auch, dass einige Probleme, die Sie als " inhärent statusbehaftet, wie das Schreiben in eine Datenbank " empfinden, unveränderliche Lösungen wie Datomic aufweisen . Dies kann überraschend sein, bis Sie verstehen, dass es sich um ein Konzept handelt, nicht unbedingt um dessen Umsetzung.
quelle
Wenn man das richtige mentale Modell abonniert, kann man besser über den Zustand nachdenken und ihn verwalten. Meiner Meinung nach ist das beste mentale Modell das Daumenkino . Sobald Sie auf diese Schaltfläche klicken, werden Sie verstehen, dass FP sich stark auf persistente Datenstrukturen stützt, die den Zustand der Welt erfassen, und dass Funktionen verwendet werden, um diesen Zustand ohne jede Veränderung zu ändern.
Rich Hickey beleuchtet diese Ideen:
Es gibt noch andere Gespräche, aber dies sollte Sie in die richtige Richtung leiten.
quelle
Beim Schreiben von großen und mittelgroßen Anwendungen habe ich es oft als nützlich empfunden, zwischen zustandsbehafteten und zustandslosen Abschnitten der Anwendung zu unterscheiden.
Die Klassen / Datenstrukturen im statusbehafteten Abschnitt speichern die Daten der Anwendung, und die Funktionen in diesem Abschnitt arbeiten mit impliziter Kenntnis der Daten der Anwendung.
Die Klassen / Datenstrukturen / Funktionen im Abschnitt "Zustandslos" sollen die rein algorithmischen Aspekte der Anwendung unterstützen. Sie haben keine implizite Kenntnis der Daten der Anwendung. Sie arbeiten rein funktional. Die zustandsbehafteten Teile der Anwendung können eine Zustandsänderung als Nebenwirkung der Ausführung von Funktionen im zustandslosen Abschnitt der Anwendung erfahren.
Der schwierigste Teil besteht darin, herauszufinden, welche Klassen / Funktionen in den zustandslosen Abschnitt und welche Klassen / Funktionen in den zustandsbehafteten Abschnitt gestellt werden sollen, und die Disziplin zu haben, sie in separate Dateien / Bibliotheken zu legen.
quelle