Monadfix -Instanz für Rand Monad
Frage
Ich möchte mit Rand Monad von Rand Monad aus unendlichem Zahlenstrom erzeugen System.random.mwc.monad. Wenn es nur eine Monadfix -Instanz für diese Monate oder eine solche Instanz geben würde:
instance (PrimMonad m) => MonadFix m where
...
Dann konnte man schreiben:
runWithSystemRandom (mfix (\ xs -> uniform >>= \x -> return (x:xs)))
Es gibt jedoch keine.
Ich ging durch Monadfix docs Aber ich sehe keine offensichtliche Möglichkeit, diese Instanz zu implementieren.
Lösung
Eine Frage: Wie möchten Sie Ihren anfänglichen Samen generieren?
Das Problem ist, dass MWS auf dem "primitiven" Paket basiert, das nur IO und streng (control.monad.st.st s) abstrahiert. Es ist nicht auch faul (control.monad.st.lazy.st s).
Vielleicht könnte man Instanzen für "primitiv" machen, um faule St. zu decken, und dann könnte MWS faul sein.
UPDATE: Ich kann diese Arbeit mit Control.monad.st.lazy durch verwenden, indem ich StrictTolazyst mithilfe von:
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)
Andere Tipps
Sie können eine Monadfix -Instanz schreiben. Der Code generiert jedoch keinen unendlichen Stream mit unterschiedlichen Zufallszahlen. Das Argument für MFIX ist eine Funktion, die aufruft uniform
genau einmal. Wenn der Code ausgeführt wird, wird er angerufen uniform
genau einmal und erstellen Sie eine unendliche Liste, die das Ergebnis enthält.
Sie können den äquivalenten IO -Code ausprobieren, um zu sehen, was passiert:
import System.Random
import Control.Monad.Fix
main = print . take 10 =<< mfix (\xs -> randomIO >>= (\x -> return (x : xs :: [Int])))
Es scheint, dass Sie einen staatlichen Zufallszahlengenerator verwenden möchten und den Generator ausführen und seine Ergebnisse träge sammeln möchten. Das ist nicht möglich, ohne sorgfältig zu verwenden unsafePerformIO
. Wenn Sie nicht schnell viele Zufallszahlen erzeugen müssen, können Sie eine reine RNG -Funktion wie z. B. verwenden randomRs
stattdessen.
(Dies wäre besser als Kommentar zur Antwort des Heargingkaros geeignet, aber es ist ein bisschen zu lang.)
MonadFix
Instanzen müssen sich anhalten mehrere Gesetze. Einer von ihnen ist links schrumpfend/dochend:
mfix (\x -> a >>= \y -> f x y) = a >>= \y -> mfix (\x -> f x y)
Dieses Gesetz erlaubt es, Ihren Ausdruck umzuschreiben als
mfix (\xs -> uniform >>= \x -> return (x:xs))
= uniform >>= \x -> mfix (\xs -> return (x:xs))
= uniform >>= \x -> mfix (return . (x :))
Verwendung eines anderen Gesetzes, Reinheit mfix (return . h) = return (fix h)
, Wir können uns weiter vereinfachen zu
= uniform >>= \x -> return (fix (x :))
und Verwendung der Standard -Monadgesetze und Umschreiben fix (x :)
wie repeat x
= liftM (\x -> fix (x :)) uniform
= liftM repeat uniform
Daher ist das Ergebnis in der Tat eine Anrufung von uniform
Und dann nur den einzelnen Wert auf unbestimmte Zeit wiederholen.