Ich werde zuerst die zweite Frage beantworten. Es gibt viele Möglichkeiten, um den veränderlichen Zustand in Haskell (und anderen FP-Sprachen) zu behandeln. Zuallererst unterstützt Haskell den mutierbaren Zustand in IO durch IORef
und mvar
Konstrukte. Diese zu verwenden, wird Programmierern aus Imperativsprachen sehr vertraut vorkommen. Es gibt auch spezialisierte Versionen wie STRef
und TMVar
, sowie veränderbare Arrays, Zeiger und verschiedene andere veränderbare Daten. Der größte Nachteil ist, dass diese in der Regel nur innerhalb von IO oder einer spezialisierten Monade verfügbar sind.
Die gebräuchlichste Methode zum Simulieren des Status in einer funktionalen Sprache besteht darin, den Status explizit als Funktionsargument und zurückgegebenen Wert zu übergeben. Zum Beispiel:
randomGen :: Seed -> (Int, Seed)
Hier randomGen
nimmt einen Samen Parameter und gibt einen neuen Samen. Jedes Mal, wenn Sie es aufrufen, müssen Sie den Seed für die nächste Iteration verfolgen. Diese Technik ist immer für das State-Passing verfügbar, wird aber schnell langweilig.
Wahrscheinlich ist der häufigste Haskell-Ansatz, eine Monade zu verwenden, um diesen Zustand zu verkapseln. Wir können randomGen
mit diesem ersetzen:
-- a Random monad is simply a Seed value as state
type Random a = State Seed a
randomGen2 :: Random Int
randomGen2 = do
seed <- get
let (x,seed') = randomGen seed
put seed'
return x
nun alle Funktionen, die ein PRNG benötigen, kann innerhalb des Zufalls Monade laufen um sie verlangen je nach Bedarf. Sie müssen nur einen Anfangszustand und die Berechnung angeben.
(Beachten Sie, dass es Funktionen gibt, die die Definition von randomGen2 erheblich verkürzen; ich wählte die explizitste Version).
Wenn Ihre zufällige Berechnung auch Zugriff auf IO
benötigt, verwenden Sie die Monade-Transformer-Version von State, StateT
.
Von besonderer Bedeutung ist die ST
Monade, die im Wesentlichen einen Mechanismus bietet, IO-spezifische Mutationen vom Rest von IO zu verkapseln. Die ST-Monade stellt STRefs bereit, die eine veränderbare Referenz auf Daten sind, und auch veränderbare Arrays.Mit ST ist es möglich, Dinge wie diese zu definieren:
randomList :: Seed -> [Int]
wo [Int] ist eine unendliche Liste von Zufallszahlen (es Zyklus werden schließlich je nach PSRG) vom Start Samen geben Sie es.
Schließlich gibt es Functional Reactive Programming. Wahrscheinlich die derzeit bekanntesten Bibliotheken dafür sind Yampa und Reactive, aber die anderen sind es wert, auch zu betrachten. Es gibt verschiedene Ansätze für einen veränderbaren Zustand innerhalb der verschiedenen Implementierungen von FRP; Von meinem leichten Gebrauch von ihnen scheinen sie oft im Konzept einem Signalrahmen ähnlich zu sein wie in QT oder Gtk + (z. B. Hinzufügen von Zuhörern für Ereignisse).
Jetzt für die erste Frage. Der größte Vorteil für mich ist, dass der änderbare Zustand auf Code-Ebene von anderem Code getrennt ist. Dies bedeutet, dass der Code den Status nicht versehentlich ändern kann, es sei denn, dies wird ausdrücklich in der Typsignatur erwähnt. Es gibt auch eine sehr gute Kontrolle des Nur-Lese-Zustands gegenüber dem Veränderlichen-Zustand (Leser-Monade vs. Zustands-Monade). Ich finde es sehr nützlich, meinen Code auf diese Weise zu strukturieren, und es ist nützlich, nur anhand der Typ-Signatur zu erkennen, ob eine Funktion unerwartet in den Status mutieren könnte.
Ich persönlich habe keine Vorbehalte gegenüber der Verwendung von veränderlichen Zustand in Haskell. Die größte Schwierigkeit ist, dass es mühsam sein kann, etwas hinzuzufügen, das es vorher nicht benötigt hat, aber das Gleiche wäre in anderen Sprachen, die ich für ähnliche Aufgaben verwendet habe (C#, Python), mühsam.
http://www.haskell.org/all_about_monads/html/statemonad.html –
Handhabungszustand in einer funktionalen Sprache beinhaltet, um die Funktionen, die den Zustand der Umgebung verläuft. Monaden vereinfachen dies. – tylermac
@tylermac Ich konnte nie Monaden verstehen, nun, ich kann nicht sagen, dass ich dumm bin, zumindest bin ich BS in CS, aber Monaden ... kennst du gute Tutorials? – Andrey