2012-01-08 4 views

Respuesta

5

La norma System.Random tiene una interfaz pura. Recomiendo envolverlo en un State g (para cualquier generador g que esté usando) para evitar enhebrar el estado; la función state hace las funciones de giro como next en acciones con estado fáciles:

next :: (RandomGen g) => g -> (Int, g) 
state :: (s -> (a, s)) -> State s a 
state next :: (RandomGen g) => State g Int 

MonadRandom El paquete se basa en la interfaz State g con envolturas pre-escritos para las funciones del generador; Creo que es bastante popular

Tenga en cuenta que todavía puede ejecutar acciones utilizando esta interfaz pura on the global RNG. MonadRandom tiene evalRandIO para este propósito.

Creo que podría escribir una instancia (huérfana) RandomGen para usar mwc-random con estos.

+1

+1 para 'MonadRandom', es el camino a seguir. – luqui

+0

@ehird ¿Cuál es aquí la fuente libre de IO de aleatoriedad que lo mantendría puro? ECC? –

+0

@JFritsch: Recuerde, pure no solo significa no IO. Una función pura debe _siempre_ devolver el mismo resultado dados los mismos argumentos. La única "fuente de aleatoriedad" es el generador o _seed_ ('g' en las firmas de tipo). – hammar

7

Me gusta el paquete mersenne-random-pure64. Por ejemplo, puede utilizar de esta manera para generar una corriente perezosa infinita de dobles aleatorios a partir de un valor de semilla:

import Data.Word (Word64) 
import Data.List (unfoldr) 
import System.Random.Mersenne.Pure64 

randomStream :: (PureMT -> (a, PureMT)) -> PureMT -> [a] 
randomStream rndstep g = unfoldr (Just . rndstep) g 

toStream :: Word64 -> [Double] 
toStream seed = randomStream randomDouble $ pureMT seed 

main = print . take 10 $ toStream 42 

usando System.Random (randoms)

Usted puede obtener una salida similar a la incorporado randoms función, que es más corto y más general (Gracias a ehird por señalarlo):

import System.Random (randoms) 
import System.Random.Mersenne.Pure64 (pureMT) 

main = print . take 10 $ randomdoubles where 
    randomdoubles :: [Double] 
    randomdoubles = randoms $ pureMT 42 

por lo que es una instancia de MonadRandom

Después de leer aproximadamente MonadRandom tengo curiosidad por cómo obtener PureMT trabajando como ejemplo de ello. Fuera de la caja no funciona, porque PureMT no crea la instancia RandomGen de la función split. Una forma de hacerlo funcionar es ajustar PureMT en un newtype y escribir una instancia personalizada split para la clase de tipo RandomGen, para la cual existe una instancia predeterminada MonadRandom.

import Control.Monad.Random 
import System.Random.Mersenne.Pure64 

getTenRandomDoubles :: Rand MyPureMT [Double] 
getTenRandomDoubles = getRandoms >>= return . take 10 

main = print $ evalRand getTenRandomDoubles g 
    where g = MyPureMT $ pureMT 42 


newtype MyPureMT = MyPureMT { unMyPureMT :: PureMT } 
myPureMT = MyPureMT . pureMT 

instance RandomGen MyPureMT where 
    next = nextMyPureMT 
    split = splitMyPureMT 

splitMyPureMT :: MyPureMT -> (MyPureMT, MyPureMT) 
splitMyPureMT (MyPureMT g) = (myPureMT s, myPureMT s') where 
    (s',g'') = randomWord64 g' 
    (s ,g') = randomWord64 g 

nextMyPureMT (MyPureMT g) = (s, MyPureMT g') where 
    (s, g') = randomInt g 
+2

Puede hacer eso para cualquier 'RandomGen' (del cual' PureMT' es una instancia), con 'randoms :: (RandomGen g, Random a) => g -> [a]'. – ehird

+0

@ehird ¡oh, no sabía nada de 'randoms'! Actualizado mi respuesta –

+1

También hay 'monad-mersenne-random' http://hackage.haskell.org/package/monad-mersenne-random construido sobre 'mersenne-random-pure64'. Tiene una propiedad agradable que permite ejecutar iteraciones monádicas en un espacio de memoria constante (consulte esta pregunta: http://stackoverflow.com/questions/3236442/). – sastanin

2

Un paquete particularmente agradable con una interfaz pura que también es adecuado para aplicaciones criptográficas y sin embargo mantiene un alto rendimiento es el paquete de cprng-aes.

Proporciona dos interfaces: Una pura determinista usando las clases de tipo de System.Random así como una interfaz IO fuerte que usa las clases de tipo del paquete Crypto-API.

Como nota al margen: generalmente preferiría los paquetes mersenne-random sobre mwc-random. Usan el algoritmo original de Mersenne Twister y en mis puntos de referencia superaron a mwc-random por un factor grande.

Cuestiones relacionadas