Wie schreibe ich eine Haskell-Funktion ohne IO in Typ sig durch Verstecken von 'Status' Änderungen

7

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?

    
Babu Srinivasan 20.05.2011, 15:32
quelle

3 Antworten

13

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.

    
Don Stewart 20.05.2011, 15:38
quelle
5

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.

    
fuz 20.05.2011 15:37
quelle
3

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

    
augustss 20.05.2011 15:38
quelle