Pregunta

Fui a través de algunos tutoriales en la mónada Estado y creo que tengo la idea.

Por ejemplo, como en este buen 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, así que puedo utilizar getRandom:

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

Pero todavía tengo que pasar la semilla al PRNG cada vez que llamo. Sé que la PRNG disponibles en implementaciones Haskell no necesita que:

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

Así que probablemente entendido bien la mónada Estado, porque lo que pude ver en la mayoría de los tutoriales no parece ser el estado "persistentes", pero sólo una forma conveniente para enhebrar estado.

Así que ... ¿Cómo puedo tener el estado que se inicializa automáticamente (posible de alguna función que utiliza tiempo y otros datos no muy predecibles), al igual que el módulo aleatoria lo hace?

Muchas gracias!

¿Fue útil?

Solución

randomRIO utiliza la mónada IO. Esto parece funcionar muy bien en el intérprete porque el intérprete también trabaja en la mónada IO. Eso es lo que está viendo en su ejemplo; realidad no se puede hacer eso en el nivel superior de código -. tendría que ponerlo en un do-expresión como todas las mónadas de todos modos

En código general se debe evitar la mónada IO, porque una vez que el código utiliza la mónada IO, que está ligado a estado externo para siempre - no se puede salir de ella (es decir, si tiene código que utiliza la mónada IO , cualquier código que llama también tiene que utilizar la mónada IO, no hay manera segura de "salir" de ella). Por lo que la mónada IO sólo debe ser usado para cosas como el acceso al entorno externo, las cosas donde se requiere absolutamente.

Para cosas como estado autónomo local, usted no debe utilizar la mónada IO. Puede utilizar la mónada State como usted ha mencionado, o puede utilizar la mónada ST. La mónada ST contiene una gran cantidad de las mismas características que la mónada IO; es decir, hay células mutables STRef, análogos a IORef. Y lo bueno de ST en comparación con IO es que cuando haya terminado, puede llamar runST en una mónada ST para obtener el resultado del cálculo de la mónada, que no se puede hacer con IO.

En cuanto a "ocultar" el estado, que apenas viene como parte de la sintaxis de las expresiones do-en Haskell para mónadas. Si usted piensa que necesita para aprobar explícitamente el estado, entonces usted no está utilizando la sintaxis mónada correctamente.

Aquí está el código que utiliza instrucción IOREF en el IO Mónada:

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

Este es el código que utiliza la mónada ST:

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

La simplicidad del código es esencialmente la misma; excepto que en este último caso podemos obtener el valor de la mónada, y en el primero no podemos sin ponerlo dentro de otro cálculo IO.

Otros consejos

secretStateValue :: IORef SomeType
secretStateValue = unsafePerformIO $ newIORef initialState
{-# NOINLINE secretStateValue #-}

Ahora accede a tu secretStateValue con readIORef y writeIORef , en la mónada IO.

  

Así que probablemente entendido bien la mónada Estado, porque lo que pude ver en la mayoría de los tutoriales no parece ser el estado "persistentes", pero sólo una forma conveniente para enhebrar estado.

La mónada estado es precisamente sobre el roscado estado a través de un cierto margen.

Si desea que el estado de nivel superior, que está fuera del lenguaje (y que tendrá que usar una variable mutable global). Nótese cómo esto probablemente complicado hilo de seguridad de su código - cómo se inicializa ese estado? ¿y cuando? Y por qué hilo?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top