haskellrandommonadsmonadfix

MonadFix instance for Rand monad


I would like to generate infinite stream of numbers with Rand monad from System.Random.MWC.Monad. If only there would be a MonadFix instance for this monad, or instance like this:

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

then one could write:

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

There isn't one though.

I was going through MonadFix docs but I don't see an obvious way of implementing this instance.


Solution

  • A question: how do you wish to generate your initial seed?

    The problem is that MWS is built on the "primitive" package which abstracts only IO and strict (Control.Monad.ST.ST s). It does not also abstract lazy (Control.Monad.ST.Lazy.ST s).

    Perhaps one could make instances for "primitive" to cover lazy ST and then MWS could be lazy.

    UPDATE: I can make this work using Control.Monad.ST.Lazy by using 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)