我在我的应用程序中使用System.Random和Random类型类生成随机数.但是我想生成一个任意长度的随机浮点列表,其函数类似于randoms :: StdGen -> Int -> ([Float], StdGen)
没有获得新发电机的限制,我可以很容易地写
randoms gen n = (take n $ randoms gen) :: [Float]
然而,这让我开始使用相同的随机生成器,这意味着如果我连续两次运行此函数,我将获得相同的列表,除非我去其他地方使用生成器获取新的生成器.
如何生成无限(或任意长度)随机值列表,同时"刷新"我的随机生成器.
Gab*_*lez 28
好吧,让我们来看看你的功能:
random :: StdGen -> (Float, StdGen) -- From System.Random
Run Code Online (Sandbox Code Playgroud)
我们可以将它包装在Statemonad中以获得有状态的计算:
state :: (s -> (a, s)) -> State s a -- From Control.Monad.Trans.State
random' :: State StdGen Float
random' = state random
Run Code Online (Sandbox Code Playgroud)
现在,我们可以使用replicateM以下方法生成一堆浮点数:
replicateM :: (Monad m) => Int -> m a -> m [a] -- From Control.Monad
randoms' :: Int -> State StdGen [Float]
randoms' n = replicateM n random'
Run Code Online (Sandbox Code Playgroud)
最后,我们打开它State来取回显式生成器传递:
randoms :: Int -> StdGen -> ([Float], StdGen)
randoms n = runState (randoms' n)
Run Code Online (Sandbox Code Playgroud)
如果将所有这些组合成一个函数定义,您将获得:
randoms :: Int -> StdGen -> ([Float], StdGen)
randoms n = runState (replicateM n (state random))
Run Code Online (Sandbox Code Playgroud)
换句话说,我们可以将过程描述为:
random在Statemonad中n次数这就是为什么monads是如此重要的概念.当通过monad接口的镜头观看时,最初看起来很棘手的事情往往是简单的计算.
小智 5
Gabriel的答案是正确的,这几乎是MonadRandom包的实现方式(使用随机生成器参数化的Monad状态).
它可以节省您每次定义它,它也带有Monad变换器,因此您可以将任何其他Monad转换为也可以生成随机值的Monad.
您的示例可以轻松实现为:
(runRand $ take n `fmap` getRandoms) :: RandomGen g => g -> ([Int], g)
Run Code Online (Sandbox Code Playgroud)
StdGen恰好是RandomGen的一个实例,所以你只需将其插入即可!