Wie kann ich Zustand in einer versteckten Weise in Haskell (wie der PRNG der Fall ist) initialisiert werden?

StackOverflow https://stackoverflow.com/questions/1121340

  •  13-09-2019
  •  | 
  •  

Frage

Ich ging durch einige Tutorials über die staatliche Monade und ich glaube, ich auf die Idee kam.

Zum Beispiel, wie in diesem netten Tutorial :

import Data.Word

type LCGState = Word32

lcg :: LCGState -> (Integer, LCGState)
lcg s0 = (output, s1) 
  where s1 = 1103515245 * s0 + 12345
        output = fromIntegral s1 * 2^16 `div` 2^32


getRandom :: State LCGState Integer
getRandom = get >>= \s0 -> let (x,s1) = lcg s0
                           in put s1 >> return x

OK, so kann ich getRandom verwenden:

*Main> runState getRandom 0
(0,12345)
*Main> runState getRandom 0
(0,12345)
*Main> runState getRandom 1              
(16838,1103527590)

Aber ich muss noch den Samen der PRNG jedes Mal passieren ich es nennen. Ich weiß, dass die in Haskell-Implementierungen verfügbar PRNG, dass nicht braucht:

Prelude> :module Random
Prelude Random> randomRIO (1,6 :: Int)
(...) -- GHC prints some stuff here
6
Prelude Random> randomRIO (1,6 :: Int)
1

Also habe ich wahrscheinlich den Staat Monade falsch verstanden, weil das, was ich in den meisten Tutorials sehen konnte scheint nicht „persistent“ Staat, sondern nur eine bequeme Art und Weise zu seinen Zustand fädeln.

So ... Wie kann ich Zustand, der automatisch initialisiert (möglich von einigen Funktion, die Zeit und andere nicht-sehr vorhersagbaren Daten), wie das Zufall Modul verwendet das?

Vielen Dank!

War es hilfreich?

Lösung

randomRIO verwendet die IO Monade. Dies scheint im Interpreter schön zu arbeiten, weil der Dolmetscher arbeitet auch in der IO Monade. Das ist, was Sie in Ihrem Beispiel sehen; Sie können nicht wirklich tun auf der obersten Ebene im Code -. Sie es trotzdem in einem Do-Ausdruck bringen würden wie alle Monaden müssen

Im allgemeinen Code sollten Sie die IO Monade vermeiden, denn wenn Ihr Code die IO Monade verwendet, es für immer zu externen Zustand gebunden ist - man kann nicht aus ihm heraus (dh, wenn Sie Code haben, der IO Monade verwendet jeder Code, die es auch nennt den IO Monade verwenden; es keinen sicheren Weg gibt, um es zu „get out“). So ist die IO Monade nur für Dinge verwendet werden, sollte die äußere Umgebung wie den Zugriff auf Dinge, wo es unbedingt erforderlich ist.

Für Dinge wie lokale Selbstversorger-Zustand, sollten Sie nicht die IO Monade verwenden. Sie können die State Monade verwenden, wie Sie erwähnt haben, oder Sie können die ST Monade verwenden. Die ST Monade enthält viele der gleichen Eigenschaften wie der IO-Monade; das heißt, es ist STRef veränderbare Zellen, die analog zu IORef. Und das Schöne an ST IO im Vergleich ist, dass, wenn Sie fertig sind, können Sie runST auf einem ST-Monade nennen das Ergebnis der Berechnung aus der Monade zu erhalten, die Sie nicht mit IO tun können.

Wie bei „versteckt“ dem Staat, die gerade kommt als Teil der Syntax der do-Ausdrücke in Haskell für Monaden. Wenn Sie denken, Sie brauchen, um explizit den Zustand übergehen, dann sind Sie nicht die Monade Syntax korrekt verwendet wird.

Hier ist Code, der IOREF im IO-Monade verwendet:

import Data.IORef
foo :: IO Int -- this is stuck in the IO monad forever
foo = do x <- newIORef 1
         modifyIORef x (+ 2)
         readIORef x
-- foo is an IO computation that returns 3

Hier ist Code, der die ST Monade verwendet:

import Control.Monad.ST
import Data.STRef
bar :: Int
bar = runST (do x <- newSTRef 1
                modifySTRef x (+ 2)
                readSTRef x)
-- bar == 3

Die Einfachheit des Codes ist im Wesentlichen gleich sind; außer dass in diesem Fall wir den Wert aus der Monade bekommen, und in den ehemaligen können wir nicht ohne sie in einer anderen IO Berechnung setzen.

scroll top