我想为整数流中的每个元素生成一个随机数列表(0,1)。我试图建立一个理解列表:
randomNums = [(i, r) | i <- [1..], r <- SR.newStdGen]
我根本无法弄清楚如何做到这一点。有人可以帮忙吗?我正在寻找的输出是原始元素,i和相关的随机浮点数。例如:
[(1, 0.20381), (2, 0.1128373), ...
答案 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)
首先,newStdGen
是IO 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
为您提供了一种方法来处理有效的惰性列表,而不会牺牲使用高级转换来操作它们的能力。