Funktionale Programmierung: Zustand vs. Neuzuordnung

stimmen
13

Ich brauche meinen Kopf Hilfe, um den Unterschied zwischen meinem aktuellen OOP Begriff des Zustandes und die Art und Weise, es wäre in einer funktionalen Sprache wie Haskell oder Clojure erfolgen.

Um ein abgedroschenes Beispiel zu verwenden, lassen Sie sich sagen, dass wir mit vereinfachten Bankkonten Objekten / structs / was auch immer zu tun hat. In einer OOP-Sprache, würde ich eine Klasse haben einen Verweis auf ein Bankkonto gehalten wird, die Instanzvariablen für Dinge wie Zinssatz haben würde, und Methoden wie setInterestRate (), die den Zustand des Objekts zu ändern und in der Regel nichts zurück. In sagen Clojure, würde ich ein Bankkonto Struktur (eine glorifizierte hashmap) haben, und spezielle Funktionen, die ein Bankkonto Parameter und andere Informationen nehmen, und gibt eine neue Struktur. Anstatt also den Zustand des ursprünglichen Objekts zu ändern, ich habe jetzt ein neues Geschäft mit den gewünschten Änderungen zurückgegeben wird.

Also ... was mache ich damit? Überschreibt jede Variable wurde Verweis auf das alte Bank-Konto? Wenn ja, hat die Vorteile gegenüber dem Stand verändernden OOP-Ansatz? Am Ende in beiden Fällen scheint es, man eine Variable, die das Objekt mit den notwendigen Änderungen verweist. Retardiert, wie ich bin, ich habe nur eine vage Vorstellung davon, was vor sich geht.

Ich hoffe, dass Sinn gemacht, vielen Dank für jede Hilfe!

Veröffentlicht am 09/12/2008 um 20:24
quelle vom benutzer
In anderen Sprachen...                            


4 antworten

stimmen
11

In einem reinen funktionalen Stil, werden Sie nie eine Variable überschreiben.

Eine Analogie wäre zu Raum-Zeit in der Physik sein. Wenn Sie die Welt als 3D betrachten, dann Objekte sind keine festen Positionen - sie bewegen sich im Laufe der Zeit. Um Mathe zu bringen auf der physischen Welt zu tragen, fügen wir daher eine zeitliche Dimension und berücksichtigen die Werte verschiedener Eigenschaften zu bestimmten Zeiten. Dabei haben wir die Objekte unserer Studie in Konstanten gemacht. Ebenso in der Programmierung gibt es eine konzeptionelle Einfachheit durch die Arbeit mit unveränderlichen Werten werden mußte. Objekte mit einer Identität in der realen Welt können als eine Folge von unveränderlichen Werten (bei steigenden Zeiten die Zustände des Objekts) modelliert werden und nicht als einen einzelnen Wert, ändert.

Natürlich sind die Details, wie die Folge von Werten zu einer „Objektidentität“ assoziieren kann ein wenig behaart sein. Haskell hat Monaden , die Sie Modellzustand lassen. Functional Reactive Programming ist ein wörtlicher Versuch Modellierungsobjekte in der Welt mit rein funktionalem Updates, dass ich denke , eine sehr vielversprechende Richtung für die Programmierung ist.

Ich werde beachten Sie, dass Clojure, im Gegensatz zu Haskell, nicht rein ist, und Sie können Variablen aktualisieren, wie Sie vorgeschlagen. Wenn Sie nur ein paar Variablen auf einem hohen Niveau zu aktualisieren, werden Sie wahrscheinlich immer noch viele der konzeptionellen Einfachheit Vorteile der funktionalen Programmierung genießen.

Beantwortet am 09/12/2008 um 21:10
quelle vom benutzer

stimmen
8

Vermutlich in der OO Welt haben Sie eine Schleife und werden diese Bankkonten immer und immer wieder als Reaktion auf Anfragen zu modifizieren. Nehmen wir an, Sie ein ganzes Portfolio von Konten haben und diese Art Portfolio haben. Dann in Haskell würden Sie eine reine Funktion schreiben

updatePortfolio :: Request -> Portfolio -> Portfolio

Und Ihre Hauptschleife könnte Anfragen von der Standardeingabe lesen und Ihr Portfolio aktuell halten. (Das Beispiel ist nicht viel, wenn Sie auch das Portfolio schreiben können, aber es ist einfacher.)

readRequest :: IO Request  -- an action that, when performed, reads a Request with side effects

main :: Portfolio -> IO ()  -- a completely useless program that updates a Portfolio in response to a stream of Requests

main portfolio = do req <- readRequest
                    main (updatePortfolio req)

und jetzt ich hoffe, dass Sie sehen, was Ihr wandelbaren Zustand passiert: in einem typischen Funktionsprogramm, das seinen Zustand ändert wird als Parameter an eine Funktion übergeben. Wenn der Zustand changess, stellen Sie einen neuen Funktionsaufruf. Der Aufruf ist in tail Position (man kann ‚richtigen Endaufruf‘ nachschlagen) und so hat es keine zusätzlichen Mittel verwenden, und in der Tat, wenn der Compiler erzeugt Assembler-Code eine Schleife erzeugt, und es wird den Zeiger auf dem halten sich ständig verändernden Portfolio in einem Register.

Dies ist ein sehr Spielzeug Beispiel, aber ich hoffe, es gibt Ihnen ein wenig von dem Geschmack einer funktionalen Sprache.

Beantwortet am 10/12/2008 um 04:57
quelle vom benutzer

stimmen
4

Also ... was mache ich damit? Überschreibt jede Variable wurde Verweis auf das alte Bank-Konto?

Ja

Wenn ja, hat die Vorteile gegenüber dem Stand verändernden OOP-Ansatz?

Nehmen wir an, die Berechnung jeglicher Aktion, die Sie auf dieser Struktur zu tun dauert eine lange Zeit und etwas passiert, auf halbem Weg, und Sie müssen wieder in die ursprüngliche Struktur oder die Berechnung wird eine Fehler zurückzukehren. Mit der Interpretation du mir von OO vorgestellt haben (mit einer Referenz, weil Sie eine unveränderliche OO Sprache haben kann), dass die Daten unbekannt korrupt --es der sein könnte, wenn nicht genügend Informationen aus dem ausgefallenen Funktionsaufruf gegeben wurde, und lässt vorschlagen es fehlgeschlagen schlecht. In einem funktionalen Ansatz wissen Sie sicher, dass Ihre ursprüngliche Datenstruktur korrekt ist --because Sie zunächst eine Kopie gemacht.

Erweitern Sie dieses Szenario in Multi-Threaded-Anwendungen. Wir können sicherstellen, dass niemand sonst die Datenstruktur verwendet wir sind, da wir alle unsere eigene Version davon haben.

Darüber hinaus können wir Platz sparen, indem Daten von der anderen Struktur verwenden, die wir aus kopieren. Ein klassisches Beispiel ist, wenn ein Element auf den Kopf einer Liste hinzugefügt wird. Wenn wir einen Zeiger auf das zweite Element haben, und einen Zeiger auf das erste Element wir nur die Größe der ersten beiden Listen mit Bezug kann (siehe unten). Ohne Unveränderlichkeit können wir dies nicht garantieren.

        b__
           |  
a -> [6|] -+-> [5|] -> [4|] -> [3|] -> [2|] -> [1|x]
Beantwortet am 09/12/2008 um 20:58
quelle vom benutzer

stimmen
1

Schauen Sie sich Haskell, die eine rein funktionale ist sprach es hat keine Neuzuordnung auch immer, sowie keine anderen Nebenwirkungen: Um IO zu tun, in der IO Monade bauen sie das tatsächlich ersetzt Real World mit einer neuen Instanz der Welt , die, beispielsweise neuen Text angezeigt in der Konsole hat.

Beantwortet am 09/12/2008 um 22:29
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more