7 Stimmen

Wie man eine Haskell-Funktion ohne IO in type sig schreibt, indem man 'Zustandsänderungen' ausblendet

Ich schrieb eine Funktion in Haskell, die ein paar Parameter wie Word32, String (ignorieren currying) und Ausgaben IO Word32 nimmt. Nun, dies ist eine Funktion im wahrsten Sinne des Wortes: für die gleichen Eingaben wird die Ausgabe immer die gleiche sein . Es gibt keine Nebeneffekte. Der Grund, warum die Funktion IO Word32 anstelle von Word32 zurückgibt, ist, dass die Funktion viele 32-Bit-Linear-Feedback-Shift-Register (lfsr) und andere Register mehrmals in einer Schleife aktualisiert, um die endgültige Word32-Ausgabe zu berechnen.

Meine Frage ist folgende: Angesichts der Tatsache, dass diese Funktion hat effektiv keine Nebenwirkungen Ist es möglich, diese Registeraktualisierungen innerhalb der Funktionsimplementierung zu verbergen, so dass die Funktion Word32 und nicht IO Word32 zurückgibt? Wenn ja, wie?

13voto

Don Stewart Punkte 136046

Ja, Haskell kann das.

Die ST-Monade

Wenn Sie tatsächlich veränderliche Zustände (Register) verwenden, die für den Beobachter außerhalb der Funktion völlig verborgen sind, dann sind Sie in die ST-Monade , eine Monade nur für Speichereffekte. Sie betreten die ST-Welt über runST und wenn Sie die Funktion beenden, sind alle Effekte garantiert nicht mehr sichtbar.

Es ist genau die richtige Rechenumgebung für die Arbeit mit lokalen, veränderlichen Zuständen.

Rein funktionaler Zustand: die Staatsmonade

Wenn Sie jedoch keine Register oder Zellen mutieren, sondern einen rein funktionalen Wert mehrmals aktualisieren, steht Ihnen eine einfachere Umgebung zur Verfügung: die Staatsmonade . Dies erlaubt keinen veränderbaren Zustand, sondern vermittelt die Illusion eines lokalen Zustands.

IO, und unsafePerformIO

Schließlich, wenn Sie lokale, veränderbare Effekte haben, wie in der ST Monade verwenden, aber aus irgendeinem Grund IO-Operationen auf diesen Zustand benötigen (z. B. über einen FFI-Aufruf), können Sie die ST Monade, mit fast ebenso viel Sicherheit, durch die Verwendung von unsafePerformIO anstelle von runST , um eine lokale IO-Umgebung einzuführen. Da die IO-Monade keine schönen Typen hat, um die Abstraktion zu erzwingen, müssen Sie sich manuell vergewissern, dass die Seiteneffekte nicht beobachtbar sein werden.

5voto

fuz Punkte 82245

Wenn Sie diese Funktion mit dem FFI importiert haben, entfernen Sie einfach die IO aus dem Rückgabetyp. Andernfalls verwenden Sie unsafePerformIO :: IO a -> a から System.IO.Unsafe . Bitte beachten Sie, dass diese Funktion eine der gefährlichsten Funktionen in Haskell ist. Benutzen Sie sie nicht, wenn Sie sich über die Konsequenzen nicht im Klaren sind. Aber für Ihren Zweck scheint sie in Ordnung zu sein.

3voto

augustss Punkte 22622

Ja, das wäre eine legitime Verwendung von unsafePerformIO. Aber es ist nur OK, wenn Sie wirklich sicher sind, dass es keine sichtbaren Auswirkungen gibt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X