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.

War es hilfreich?

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top