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.

Était-ce utile?

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top