par exemple pour MonadFix Rand monade
Question
Je voudrais générer flux infini de nombres avec Rand monade System.Random.MWC.Monad . Si seulement il y aurait une instance MonadFix pour cette monade, ou par exemple comme ceci:
instance (PrimMonad m) => MonadFix m where
...
alors on pourrait écrire:
runWithSystemRandom (mfix (\ xs -> uniform >>= \x -> return (x:xs)))
Il n'y a pas un bien.
Je traversais MonadFix docs mais je ne vois pas de façon évidente de mettre en œuvre cette instance.
La solution
Une question: comment voulez-vous générer votre graine initiale
Le problème est que MWS est construit sur le paquet « primitive » qui fait abstraction seulement IO et strict (Control.Monad.ST.ST s). Il ne aussi abstrait paresseux (Control.Monad.ST.Lazy.ST s).
Peut-être on pourrait faire des cas pour « primitif » pour couvrir ST paresseux et MWS pourrait être paresseux.
Mise à jour: Je peux faire ce travail en utilisant Control.Monad.ST.Lazy en utilisant 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)
Autres conseils
Vous pouvez écrire une instance MonadFix. Cependant, le code ne génère pas un flux infini de nombres aléatoires distincts. L'argument de mfix est une fonction qui appelle uniform
exactement une fois. Lorsque le code est exécuté, il appellera uniform
exactement une fois, et créer une liste infinie contenant le résultat.
Vous pouvez essayer le code IO équivalent pour voir ce qui se passe:
import System.Random
import Control.Monad.Fix
main = print . take 10 =<< mfix (\xs -> randomIO >>= (\x -> return (x : xs :: [Int])))
Il semble que vous souhaitez utiliser un générateur de nombres aléatoires stateful, et que vous voulez exécuter le générateur et de recueillir paresseusement ses résultats. Ce n'est pas possible sans l'utilisation prudente des unsafePerformIO
. À moins que vous devez produire beaucoup de nombres aléatoires rapidement, vous pouvez utiliser une fonction pure RNG tels que randomRs
à la place.
(Ce serait mieux adapté comme commentaire à la réponse de Dissipateur, mais il est un peu trop long.)
instances de MonadFix
doivent se conformer à plusieurs lois . L'un d'eux est gauche rétrécit / thightening :
mfix (\x -> a >>= \y -> f x y) = a >>= \y -> mfix (\x -> f x y)
Cette loi permet de réécrire votre expression
mfix (\xs -> uniform >>= \x -> return (x:xs))
= uniform >>= \x -> mfix (\xs -> return (x:xs))
= uniform >>= \x -> mfix (return . (x :))
En utilisant une autre loi, pureté mfix (return . h) = return (fix h)
, nous pouvons simplifier davantage à
= uniform >>= \x -> return (fix (x :))
et en utilisant les lois standards monade et la réécriture fix (x :)
comme repeat x
= liftM (\x -> fix (x :)) uniform
= liftM repeat uniform
Par conséquent, le résultat est en effet une invocation de uniform
puis que répéter indéfiniment la seule valeur.