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