Pregunta

Me gustaría generar un flujo infinito de números con Rand Monad de System.random.mwc.monad. Si tan solo hubiera una instancia de Monadfix para esta mónada, o una instancia como esta:

instance (PrimMonad m) => MonadFix m where
     ...

Entonces uno podría escribir:

runWithSystemRandom (mfix (\ xs -> uniform >>= \x -> return (x:xs)))

Aunque no hay uno.

Estaba pasando por Monadfix documentos Pero no veo una forma obvia de implementar esta instancia.

¿Fue útil?

Solución

Una pregunta: ¿Cómo desea generar su semilla inicial?

El problema es que MWS se basa en el paquete "primitivo" que abstrae solo io y estricto (control.monad.st.st s). Tampoco abstrae perezoso (control.monad.st.lazy.st s).

Quizás uno podría hacer instancias para que "primitivo" cubra el st de lazy y luego los MW podrían ser perezosos.

ACTUALIZACIÓN: Puedo hacer que esto funcione usando control.monad.st.lazy usando stricttolazyst:

module Main where

import Control.Monad(replicateM)
import qualified Control.Monad.ST as S
import qualified Control.Monad.ST.Lazy as L
import qualified System.Random.MWC as A

foo :: Int -> L.ST s [Int]
foo i = do rest <- foo $! succ i
           return (i:rest)

splam :: A.Gen s -> S.ST s Int
splam = A.uniformR (0,100)

getS :: Int -> S.ST s [Int]
getS n = do gen <- A.create
            replicateM n (splam gen)

getL :: Int -> L.ST s [Int]
getL n = do gen <- createLazy
            replicateM n (L.strictToLazyST (splam gen))

createLazy :: L.ST s (A.Gen s)
createLazy = L.strictToLazyST A.create

makeLots :: A.Gen s -> L.ST s [Int]
makeLots gen = do x <- L.strictToLazyST (A.uniformR (0,100) gen)
                  rest <- makeLots gen
                  return (x:rest)

main = do
  print (S.runST (getS 8))
  print (L.runST (getL 8))
  let inf = L.runST (foo 0) :: [Int]
  print (take 10 inf)
  let inf3 = L.runST (createLazy >>= makeLots) :: [Int]
  print (take 10 inf3)

Otros consejos

Puedes escribir una instancia de Monadfix. Sin embargo, el código no generará un flujo infinito de números aleatorios distintos. El argumento a MFIX es una función que llama uniform Exactamente una vez. Cuando se ejecute el código, llamará uniform Exactamente una vez, y cree una lista infinita que contenga el resultado.

Puede probar el código IO equivalente para ver qué sucede:

import System.Random
import Control.Monad.Fix
main = print . take 10 =<< mfix (\xs -> randomIO >>= (\x -> return (x : xs :: [Int])))

Parece que desea utilizar un generador de números aleatorios con estado, y desea ejecutar el generador y recopilar sus resultados perezosamente. Eso no es posible sin un uso cuidadoso de unsafePerformIO. A menos que necesite producir muchos números aleatorios rápidamente, puede usar una función RNG pura como randomRs en cambio.

(Esto sería más adecuado como un comentario a la respuesta de Heatsink, pero es demasiado largo).

MonadFix las instancias deben adherirse a Varias leyes. Uno de ellos es Izquierda que se encoge/thightening:

mfix (\x -> a >>= \y -> f x y)  =  a >>= \y -> mfix (\x -> f x y)

Esta ley permite reescribir su expresión como

mfix (\xs -> uniform >>= \x -> return (x:xs))
= uniform >>= \x -> mfix (\xs -> return (x:xs))
= uniform >>= \x -> mfix (return . (x :))

Usando otra ley, pureza mfix (return . h) = return (fix h), podemos simplificar aún más a

= uniform >>= \x -> return (fix (x :))

y usar las leyes de mónadas estándar y la reescritura fix (x :) como repeat x

= liftM (\x -> fix (x :)) uniform
= liftM repeat uniform

Por lo tanto, el resultado es de hecho una invocación de uniform Y luego simplemente repitiendo el valor único indefinidamente.

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