Ich habe eine Funktion in haskell geschrieben, die ein paar Parameter wie Word32, String (Curry ignorieren) und IO Word32 ausgibt. Nun, dies ist eine Funktion im eigentlichen Sinne: Für die gleichen Eingaben ist die Ausgabe immer die gleiche . Es gibt keine Nebenwirkungen. Der Grund, warum die Funktion IO Word32 anstelle von Word32 zurückgibt, besteht darin, dass die Funktion viele 32-Bit-Schieberegister (lfsr) und andere Register mehrmals in einer Schleife aktualisiert, um die endgültige Word32-Ausgabe zu berechnen.
Meine Frage ist dies: Angesichts der Tatsache, dass diese Funktion effektiv keine Nebenwirkungen hat , ist es möglich, diese Register-Updates in der Funktionsimplementierung zu verbergen, so dass die Funktion Word32 und nicht IO Word32 zurückgibt? Wenn ja, wie?
Ja! Haskell kann das tun.
Die ST-Monade
Wenn Sie tatsächlich veränderliche Zustände (Register) verwenden, die dem Beobachter außerhalb der Funktion vollständig verborgen sind, dann befinden Sie sich in die ST-Monade , eine Monade nur für Memory-Effekte. Sie geben die ST-Welt über runST
ein, und wenn Sie die Funktion verlassen, sind alle Effekte garantiert nicht sichtbar.
Es ist genau die richtige Rechenumgebung für das Arbeiten mit einem lokalen, veränderbaren Zustand.
Rein funktionaler Zustand: die Staatsmonade
Wenn Sie jedoch nicht wirklich Register oder Zellen mutieren, sondern einen rein funktionalen Wert mehrmals aktualisieren, ist eine einfachere Umgebung verfügbar: die Staatsmonade . Dies erlaubt keinen veränderlichen Zustand, sondern gibt eine Illusion des lokalen Zustands.
IO und unsafePerformIO
Schließlich, wenn Sie lokale, veränderbare Effekte haben, wie in der ST
Monade, aber aus dem einen oder anderen Grund, werden Sie IO-Operationen für diesen Zustand benötigen (zB über einen FFI-Aufruf), die Sie simulieren können die ST
-Monade, mit fast ebenso hoher Sicherheit, indem unsafePerformIO
anstelle von runST
verwendet wird, um eine lokale IO-Umgebung einzuführen. Da die IO-Monade keine schönen Typen hat, um die Abstraktion zu erzwingen, müssen Sie manuell sicherstellen, dass die Nebenwirkungen nicht beobachtbar sind.
Wenn Sie diese Funktion mithilfe des FFI importiert haben, entfernen Sie einfach IO
aus dem Rückgabetyp. Andernfalls verwende unsafePerformIO :: IO a -> a
von System.IO.Unsafe
. Bitte beachten Sie, dass diese Funktion eine der gefährlichsten Funktionen in Haskell ist. Benutze es nicht, wenn du dir über die Konsequenzen nicht sicher bist. Aber für deinen Zweck scheint es in Ordnung zu sein.
Tags und Links haskell functional-programming monads unsafe-perform-io referential-transparency