根据需要为无限列表中的每个元素生成随机数

时间:2013-04-28 15:32:29

标签: haskell

我想为整数流中的每个元素生成一个随机数列表(0,1)。我试图建立一个理解列表:

randomNums = [(i, r) | i <- [1..], r <- SR.newStdGen] 

我根本无法弄清楚如何做到这一点。有人可以帮忙吗?我正在寻找的输出是原始元素,i和相关的随机浮点数。例如:

[(1, 0.20381), (2, 0.1128373), ...

3 个答案:

答案 0 :(得分:4)

只需使用zip配对它们:

Prelude System.Random> let g = mkStdGen 42

Prelude System.Random> take 10 . zip [1..] . randomRs (0.0,1.0) $ g
[(1,0.11040701265689151),(2,0.8453984927258916),(3,0.30778213446209723),(4,0.781
3880826070412),(5,0.5242581917029475),(6,0.5196911001158159),(7,0.20084688456283
112),(8,0.47947729750989876),(9,0.3240164101179728),(10,6.1566369505963836e-2)]

正如你所看到的,这些并不是随机的;使用相同的初始参数(此处为42),将生成相同的序列:

import System.Random

randomNums :: [a] -> Int -> [(a, Float)]
randomNums list initVal = zip list . randomRs (0.0,1.0) . mkStdGen $ initVal

如果您在main内使用此功能,您还可以随机化initVal值本身,

main = do 
  ....
  initVal <- randomIO :: IO Int
  .... -- use initVal ....

答案 1 :(得分:2)

首先,newStdGenIO StdGen,所以你根本不能在纯函数中使用它,只能在IO monad中使用它。你可以让你的函数返回IO [(Int,Double)],但这不是很好,它会将所有内容都归入IO。我建议改为使用Rand monad

randomNums :: RandomGen g => Rand g [(Int,Double)]
randomNums = do
    randDoubles <- getRandoms
    return $ zip [1..] randDoubles

或只是

randomNums = fmap (zip [1..]) getRandoms

请注意,Rand只是随机生成器的读者monad(又称函数),因此您可以轻松地在没有MonadRandom包的情况下重写它:

randomNums :: RandomGen g => g -> [(Int,Double)]
randomNums = zip [1..] . randoms
只有当你有多个需要随机发生器的东西时,使用这种签名会不那么令人愉快; Rand monad自动负责分发它们。使用显式功能,您将不断调用split,这很快就会变得混乱。

答案 2 :(得分:1)

如果你想要一个纯粹的random列表,那么使用WillNess的方法。如果你想要一个不纯的列表,那么使用pipes库懒洋洋地输入一个不纯的列表:

import Control.Proxy
import Control.Proxy.Trans.State
import System.Random

randomNums :: (Proxy p) => () -> Producer p (Int, Double) IO r
randomNums () = evalStateP 0 $ forever $ do
    i <- get
    r <- lift $ randomRIO (0, 1)
    respond (i, r)
    put $! i + 1

您通过提供适当的转换和消费阶段来读出列表。例如,如果你想获取前10个元素并打印它们,你可以写:

>>> runProxy $ randomNums >-> takeB_ 10 >-> printD
(0,0.2204881851502879)
(1,0.2507730220341101)
(2,0.8870240857313229)
(3,0.5556581036216822)
(4,0.6564558289397481)
(5,0.7499290459359478)
(6,0.10963804170328961)
(7,9.475221797586297e-2)
(8,9.342816284834865e-2)
(9,0.23343178814756815)

pipes为您提供了一种方法来处理有效的惰性列表,而不会牺牲使用高级转换来操作它们的能力。