Rand monad的MonadFix实例

时间:2011-03-19 22:15:50

标签: haskell random monads monadfix

我想用来自System.Random.MWC.Monad的Rand monad生成无限的数字流。如果只有这个monad的MonadFix实例,或者像这样的实例:

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

然后可以写:

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

虽然没有。

我正在经历MonadFix docs,但我没有看到实现此实例的明显方法。

3 个答案:

答案 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的一次调用,然后无限期地重复单个值。