Domanda

Vorrei generare un flusso infinito di numeri con Rand Monad da System.random.mwc.monad. Se solo ci sarebbe un'istanza Monadfix per questa monade, o istanza come questa:

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

Quindi si potrebbe scrivere:

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

Non ce n'è uno però.

Stavo attraversando Monadfix Docs Ma non vedo un modo ovvio di implementare questa istanza.

È stato utile?

Soluzione

Una domanda: come desideri generare il tuo seme iniziale?

Il problema è che MWS è costruito sul pacchetto "primitivo" che estrae solo IO e rigoroso (control.monad.st.st s). Non è anche astratto Lazy (Control.Monad.st.lazy.st S).

Forse si potrebbero fare casi per "primitivi" per coprire Lazy ST e quindi MWS potrebbe essere pigro.

AGGIORNAMENTO: posso fare questo lavoro utilizzando control.monad.st.lazy usando StrictoLazyst:

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)

Altri suggerimenti

Puoi scrivere un'istanza MonadFix. Tuttavia, il codice non genererà un flusso infinito di numeri casuali distinti. L'argomento su MFIX è una funzione che chiama uniform Esattamente una volta. Quando il codice viene eseguito, chiamerà uniform Esattamente una volta e crea un elenco infinito contenente il risultato.

Puoi provare il codice IO equivalente per vedere cosa succede:

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

Sembra che tu voglia utilizzare un generatore di numeri casuali statali e vuoi eseguire il generatore e raccogliere pigramente i suoi risultati. Non è possibile senza un uso attento di unsafePerformIO. A meno che tu non abbia bisogno di produrre molti numeri casuali rapidamente, è possibile utilizzare una funzione RNG pura come randomRs invece.

(Questo sarebbe più adatto come un commento alla risposta di HeatSink, ma è un po 'troppo lungo.)

MonadFix Le istanze devono aderire Diverse leggi. Uno di loro è a sinistra che si restringe/thighinging:

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

Questa legge consente di riscrivere la tua espressione come

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

Usando un'altra legge, purezza mfix (return . h) = return (fix h), possiamo semplificare ulteriormente

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

e usando le leggi standard della monade e la riscrittura fix (x :) come repeat x

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

Pertanto, il risultato è davvero un'invocazione di uniform E poi ripetere il valore singolo indefinitamente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top