MonadFix instance for nun

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

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

then we could write:

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

There is not one.

I went through the MonadFix docs , but I don't see an obvious way to implement this instance.

+4
source share
3 answers

Question: how do you want to generate an initial seed?

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

Perhaps one could give examples for the “primitive” to cover the lazy ST, and then the MWS could be lazy.

UPDATE: I can do this work with Control.Monad.ST.Lazy 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) 
+3
source

You can write a copy of MonadFix. However, the code will not generate an endless stream of various random numbers. The mfix argument is a function that calls uniform exactly once. When the code is run, it will call uniform exactly once and create an endless list containing the result.

You can try the equivalent I / O code to see what happens:

 import System.Random import Control.Monad.Fix main = print . take 10 =<< mfix (\xs -> randomIO >>= (\x -> return (x : xs :: [Int]))) 

It seems you want to use a state random number generator, and you want to run the generator and get its results lazily. This is not possible without careful use of unsafePerformIO . If you don’t need to quickly create many random numbers, you can use a pure RNG function, for example randomRs .

+6
source

(This is best suited for comments on the answer to the radiator, but it takes too long.)

MonadFix instances must adhere to several laws . One of them remains compressed / addictive:

 mfix (\x -> a >>= \y -> fxy) = a >>= \y -> mfix (\x -> fxy) 

This law allows you to rewrite your expression as

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

Using another law, the purity of mfix (return . h) = return (fix h) , we can simplify it further

 = uniform >>= \x -> return (fix (x :)) 

and using standard monad laws and rewriting fix (x :) as repeat x

 = liftM (\x -> fix (x :)) uniform = liftM repeat uniform 

Therefore, the result is really one uniform call, and then just the same value is repeated endlessly.

+2
source

Source: https://habr.com/ru/post/1344409/


All Articles