我想用来自System.Random.MWC.Monad的Rand monad生成无限的数字流。如果只有这个monad的MonadFix实例,或者像这样的实例:
instance (PrimMonad m) => MonadFix m where
...
然后可以写:
runWithSystemRandom (mfix (\ xs -> uniform >>= \x -> return (x:xs)))
虽然没有。
我正在经历MonadFix docs,但我没有看到实现此实例的明显方法。
答案 0 :(得分:6)
您可以编写MonadFix实例。但是,代码不会生成不同的随机数流。 mfix的参数是一个只调用uniform
一次的函数。运行代码时,它将只调用uniform
一次,并创建一个包含结果的无限列表。
您可以尝试使用等效的IO代码来查看会发生什么:
import System.Random
import Control.Monad.Fix
main = print . take 10 =<< mfix (\xs -> randomIO >>= (\x -> return (x : xs :: [Int])))
您似乎想要使用有状态随机数生成器,并且您希望运行生成器并懒惰地收集其结果。如果不仔细使用unsafePerformIO
,这是不可能的。除非你需要快速生成许多随机数,否则你可以使用纯粹的RNG函数,例如randomRs
。
答案 1 :(得分:3)
一个问题:您希望如何生成初始种子?
问题是MWS建立在“原始”包上,它只抽象IO和严格(Control.Monad.ST.ST s)。它也不抽象懒惰(Control.Monad.ST.Lazy.ST s)。
也许有人可以让“原始”的实例覆盖懒惰ST,然后MWS可能会变得懒惰。
更新:我可以使用strictToLazyST使用Control.Monad.ST.Lazy来完成这项工作:
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)
答案 2 :(得分:2)
(这可能更适合作为对Heatsink答案的评论,但它有点太长了。)
MonadFix
个实例必须遵守several laws。其中一个是左萎缩/紧缩:
mfix (\x -> a >>= \y -> f x y) = a >>= \y -> mfix (\x -> f x y)
此法律允许将您的表达重写为
mfix (\xs -> uniform >>= \x -> return (x:xs))
= uniform >>= \x -> mfix (\xs -> return (x:xs))
= uniform >>= \x -> mfix (return . (x :))
使用其他法律,纯度 mfix (return . h) = return (fix h)
,我们可以进一步简化为
= uniform >>= \x -> return (fix (x :))
并使用标准monad法律并将fix (x :)
重写为repeat x
= liftM (\x -> fix (x :)) uniform
= liftM repeat uniform
因此,结果确实是uniform
的一次调用,然后无限期地重复单个值。