Wie erstelle ich ein System mit den folgenden Funktionen :
- Verwendung reiner Funktionen mit unveränderlichen Objekten.
- Übergeben Sie nur Daten an eine Funktion, die die Funktion benötigt, nicht mehr (dh kein großes Objekt für den Anwendungsstatus).
- Vermeiden Sie zu viele Argumente für Funktionen.
- Vermeiden Sie es, neue Objekte nur zum Packen und Entpacken von Parametern in Funktionen zu erstellen, um zu vermeiden, dass zu viele Parameter an Funktionen übergeben werden. Wenn ich mehrere Elemente in eine Funktion als ein einzelnes Objekt packen möchte, möchte ich, dass dieses Objekt Eigentümer dieser Daten ist und nicht vorübergehend erstellt wird
Mir scheint, die Staatsmonade verstößt gegen Regel Nr. 2, obwohl es nicht offensichtlich ist, weil sie durch die Monade eingewebt ist.
Ich habe das Gefühl, dass ich Objektive irgendwie benutzen muss, aber für nicht-funktionale Sprachen wird sehr wenig darüber geschrieben.
Hintergrund
Als Übung konvertiere ich eine meiner vorhandenen Anwendungen von einem objektorientierten Stil in einen funktionalen Stil. Das erste, was ich versuche, ist, so viel wie möglich aus dem inneren Kern der Anwendung herauszuholen.
Eine Sache, die ich gehört habe, ist, wie man "Staat" in einer rein funktionalen Sprache verwaltet, und ich glaube, dass dies von staatlichen Monaden getan wird, ist, dass man logischerweise eine reine Funktion nennt, "den Staat übergeben" world as it is ", wenn die Funktion zurückkehrt, kehrt sie zu Ihnen zurück, wie sich der Zustand der Welt geändert hat.
Um zu veranschaulichen, wie Sie eine "Hallo-Welt" auf rein funktionale Weise erstellen können, übergeben Sie in Ihrem Programm den Status des Bildschirms und erhalten den Status des Bildschirms mit der Aufschrift "Hallo-Welt" zurück. Technisch gesehen rufen Sie also eine reine Funktion auf, und es gibt keine Nebenwirkungen.
Darauf basierend habe ich meine Anwendung durchgesehen und: 1. Zuerst habe ich meinen gesamten Anwendungsstatus in ein einziges globales Objekt (GameState) gestellt. 2. Zweitens habe ich GameState unveränderlich gemacht. Du kannst es nicht ändern. Wenn Sie eine Änderung benötigen, müssen Sie eine neue erstellen. Ich habe dazu einen Copy-Konstruktor hinzugefügt, der optional ein oder mehrere Felder übernimmt, die sich geändert haben. 3. Zu jeder Anwendung übergebe ich den GameState als Parameter. Innerhalb der Funktion erstellt es, nachdem es getan hat, was es tun wird, einen neuen GameState und gibt ihn zurück.
Wie ich einen reinen Funktionskern und eine Schleife an der Außenseite habe, die diesen GameState in die Haupt-Workflow-Schleife der Anwendung einspeist.
Meine Frage:
Mein Problem ist nun, dass der GameState ungefähr 15 verschiedene unveränderliche Objekte hat. Viele der Funktionen auf der niedrigsten Ebene wirken sich nur auf wenige dieser Objekte aus, z. Nehmen wir also an, ich habe eine Funktion, die die Punktzahl berechnet. Heute wird der GameState an diese Funktion übergeben, die die Punktzahl ändert, indem ein neuer GameState mit einer neuen Punktzahl erstellt wird.
Daran scheint etwas nicht zu stimmen. Die Funktion benötigt nicht das gesamte GameState. Es wird nur das Score-Objekt benötigt. Also habe ich es aktualisiert, um die Partitur zu übergeben und nur die Partitur zurückzugeben.
Das schien Sinn zu machen, also ging ich mit anderen Funktionen weiter. Für einige Funktionen müsste ich 2, 3 oder 4 Parameter vom GameState übergeben, aber da ich das Muster bis zum äußeren Kern der Anwendung verwendet habe, übergebe ich immer mehr den Anwendungsstatus. Wie oben in der Workflow-Schleife würde ich eine Methode aufrufen, die eine Methode usw. aufruft, bis zu dem Punkt, an dem die Punktzahl berechnet wird. Das bedeutet, dass die aktuelle Punktzahl durch alle diese Ebenen geleitet wird, nur weil eine Funktion ganz unten die Punktzahl berechnet.
So, jetzt habe ich Funktionen mit manchmal Dutzenden von Parametern. Ich könnte diese Parameter in ein Objekt einfügen, um die Anzahl der Parameter zu verringern, aber dann möchte ich, dass diese Klasse der Master-Speicherort des Status der Statusanwendung ist und nicht ein Objekt, das zum Zeitpunkt des Aufrufs einfach erstellt wurde, um ein Übergeben zu vermeiden in mehreren Parametern, und packen Sie sie dann aus.
Jetzt frage ich mich, ob das Problem ist, dass meine Funktionen zu tief verschachtelt sind. Dies ist das Ergebnis des Wunsches nach kleinen Funktionen. Deshalb überarbeite ich, wenn eine Funktion zu groß wird, und teile sie in mehrere kleinere Funktionen auf. Dies führt jedoch zu einer tieferen Hierarchie, und alles, was in die inneren Funktionen übergeht, muss an die äußere Funktion übergeben werden, auch wenn die äußere Funktion diese Objekte nicht direkt bearbeitet.
Es schien, als würde dieses Problem vermieden, indem man den GameState einfach auf dem Weg dahin weitergab. Aber ich komme auf das ursprüngliche Problem zurück, mehr Informationen an eine Funktion zu übergeben, als die Funktion benötigt.