4

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

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

然后可以写:

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

不过一个也没有。

我正在浏览MonadFix 文档,但我没有看到实现此实例的明显方法。

4

3 回答 3

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代替。

于 2011-03-20T01:50:15.370 回答
3

一个问题:您希望如何生成初始种子?

问题是 MWS 是建立在“原始”包上的,它只抽象 IO 和严格(Control.Monad.ST.ST s)。它也不抽象惰性(Control.Monad.ST.Lazy.ST s)。

也许可以为“原始”创建实例以涵盖惰性 ST,然后 MWS 可能是惰性的。

更新:我可以使用 Control.Monad.ST.Lazy 通过使用 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)
于 2011-03-21T18:34:59.430 回答
3

(这更适合作为对 Heatsink 答案的评论,但它有点太长了。)

MonadFix事例必须遵守几项法律。其中之一是收缩/变紧

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 :))

并使用标准的单子定律并重写fix (x :)repeat x

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

因此,结果确实是一次调用,uniform然后只是无限期地重复单个值。

于 2014-09-14T07:32:51.870 回答