Was ist der * richtige * Weg, um einen POST in FP zu behandeln?

8

Ich fange gerade mit FP an und ich benutze Scala, was vielleicht nicht der beste Weg ist, da ich immer wieder auf einen imperativen Stil zurückgreifen kann, wenn es schwierig wird. Ich würde es einfach nicht tun. Ich habe eine sehr spezifische Frage, die auf eine größere Lücke in meinem Verständnis von FP hinweist.

Wenn eine Webanwendung eine GET-Anforderung verarbeitet, möchte der Benutzer Informationen, die bereits auf der Website vorhanden sind. Die Anwendung muss die Daten nur irgendwie verarbeiten und formatieren. Der FB Weg ist klar.

Wenn eine Webanwendung eine POST-Anfrage verarbeitet, möchte der Benutzer die auf der Site gespeicherten Informationen ändern. Es stimmt, die Informationen werden normalerweise nicht in Anwendungsvariablen gespeichert, sie befinden sich in einer Datenbank oder einer Flat-Datei, aber trotzdem habe ich das Gefühl, dass ich nicht grokking FP richtig bin.

Gibt es ein Muster für die Handhabung von Updates für statische Daten in einer FP-Sprache?

Mein vages Bild davon ist, dass die Anwendung die Anfrage und den dann aktuellen Stand der Site erhält. Die Anwendung erledigt ihre Aufgabe und gibt den neuen Standort zurück. Wenn sich der aktuelle Site-Status seit dem Start der Anwendung nicht geändert hat, wird der neue Status zum aktuellen Status und die Antwort wird zurück an den Browser gesendet (das ist mein dunkles Bild von Clojures Stil); wenn der aktuelle Zustand geändert wurde (durch einen anderen Thread, nun, etwas anderes passiert ...

    
Malvolio 13.01.2011, 02:30
quelle

4 Antworten

6

Eine Möglichkeit, mit dieser Art von Problemen in einer reinen FP-Umgebung umzugehen, sind Monaden wie in Haskell (zB IO und State), aber es gibt Alternativen wie "eindeutige Typen" (die nur einen Verweis auf einen Wert zulassen) in Clean .

Es gibt nicht viel zu grok hier: Wenn Sie einen veränderlichen Zustand haben, dann müssen Sie irgendwie den Zugriff darauf beschränken, so dass jede Änderung dieses Zustands wahrgenommen wird als eine "neue Version" dieser Struktur aus dem Rest des Programms. Z.B. Sie können sich Haskells IO als "Rest der Welt" vorstellen, aber mit einer Art Uhr, die daran befestigt ist. Wenn Sie etwas mit IO machen, tickt die Uhr, und Sie sehen nie wieder dasselbe IO. Das nächste Mal, wenn du es berührst, ist es ein anderes IO, eine andere Welt, in der alles, was du getan hast, bereits passiert ist.

Im wirklichen Leben kann man "sehen", wie sich die Dinge in einem Film "verändern" - das ist die imperative Ansicht. Aber wenn Sie den Film greifen, sehen Sie nur eine Reihe von kleinen unveränderlichen Bildern, ohne irgendeine Spur von "Veränderung" - das ist die FP-Ansicht. Beide Ansichten sind gültig und in ihrem Kontext "wahr".

Wenn Sie jedoch Scala verwenden, können einen änderbaren Status haben - hier kein Problem. Scala braucht dafür keine spezielle Handhabung, und es ist nichts falsch daran, es zu benutzen (obwohl es als "guter Stil" angesehen wird, die "unreinen" Stellen so klein wie möglich zu halten).

    
Landei 13.01.2011 08:29
quelle
3

Die Antwort ist Monaden. Konkret würden der Staat und die Monaden dies vollständig handhaben.

Hier ist ein Beispiel, wie das funktionieren würde:

%Vor%

Beachten Sie, dass es keine einzige Sache gibt, die im Programm änderbar ist, und es wird jedoch die "Datenbank" (repräsentiert durch eine unveränderliche Map ) solange ändern, bis kein Speicher mehr zur Verfügung steht. Das IO -Objekt simuliert hypothetische HTTP-PUT-Anforderungen, indem Paare von zufällig generierten Schlüsseln und Werten zugeführt werden.

Dies ist also die allgemeine Struktur eines funktionalen Programms, das HTTP PUT verarbeitet und eine Datenbank einspeist. Stellen Sie sich eine Datenbank als unveränderliches Objekt vor - jedes Mal, wenn Sie sie "aktualisieren", erhalten Sie ein neues Datenbankobjekt.

    
Daniel C. Sobral 13.01.2011 16:10
quelle
3

Die idiomatische FP-Antwort auf asynchrone Zustandsänderungen über das Internet ist Fortsetzungsstil , denke ich : Die aktuelle running-Funktion wird als eine continuation -Funktion bereitgestellt, deren Aufruf mit Argumenten aus der aktuellen Berechnung (analog zum Imperativ return ) den Zustand darstellt -passing.

Auf das Web angewendet bedeutet dies, dass, wenn der Server Eingaben vom Benutzer benötigt, nur die Fortführung pro Sitzung gespeichert wird. Wenn der Benutzer mit einigen Informationen antwortet, wird die gespeicherte Fortsetzung wiederhergestellt, die von ihm bereitgestellte Eingabe wird durch eine Berechnung verarbeitet, und sie wird dann als Wert der Fortsetzung zurückgegeben.

Sie können hier ein Beispiel für ein fortlaufendes Webanwendungs-Framework finden. Eine ausführliche Beschreibung der Idee auf hoher Ebene ist hier . Siehe auch die Fülle an Ressourcen und FP-Anwendungen, die diese hier implementieren .

Continuutations werden in Scala ab 2.8 unterstützt, und es gibt ein 200-300 LoC Beispiel eines Webservers im fortsetzenden Stil in die Verteilung.

    
huitseeker 16.01.2011 22:13
quelle
-1

Hinweis: Scala kenne ich überhaupt nicht, also rate ich nur die Syntax aus Beispielen.

Hier ist eine praktische Möglichkeit, eine Karte zu implementieren:

%Vor%

Anstelle einer traditionellen Datenstruktur kann eine Karte nur eine Funktion sein. Um Einträge aus der Karte hinzuzufügen oder zu entfernen, wird eine Funktion mit der vorhandenen Karte erstellt, um eine neue Karte zu erhalten.

Ich denke auch gerne an solche Webapps. Eine Webanwendung konvertiert Anfragen in Transaktionen. Eine Transaktion ändert einen Status in einen anderen, aber sie kann auf den aktuellen Status oder einen früheren Status oder einen unbekannten zukünftigen Status angewendet werden. Transaktionen allein sind nicht sinnvoll; Irgendetwas muss sie sequenzieren und nacheinander anwenden. Aber der Request-Handler muss gar nicht darüber nachdenken.

Betrachten Sie als Beispiel, wie die Happstack -Rahmenmodelle aussehen. Eine eingehende Anfrage wird an einen Handler weitergeleitet, der innerhalb einer Monade läuft. Dank teilweise TH Magie, serialisiert das Framework das resultierende mote und fügt es dem Ende des wachsenden Transaktionslogs hinzu. Um den neuesten Status zu bestimmen, kann man einfach durch die Protokolldatei gehen und Transaktionen nacheinander anwenden. (Happstack kann auch "Checkpoints" schreiben, aber für den Betrieb sind sie nicht unbedingt notwendig.)

    
ephemient 13.01.2011 04:49
quelle