为无限列表中的每个元素生成随机数
我想为整数流中的每个元素生成一个随机数列表(0,1)。我试图建立一个理解列表:为无限列表中的每个元素生成随机数
randomNums = [(i, r) | i <- [1..], r <- SR.newStdGen]
我简直无法弄清楚如何做到这一点。谁能帮忙?我正在寻找的输出是原始元素,我和一个相关的随机浮点数。例如:
[(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 ....
这怎么能在主要功能中使用?代码在GHCi内部工作,但是当我尝试在main中运行时出错,如'print $ randomNums [1..10] 3' – turtle 2013-04-28 16:09:51
@turtle我已经更改了类型签名。现在试试。 – 2013-04-28 16:10:37
首先,newStdGen
是IO StdGen
,所以你不能在所有的纯函数中使用它,只有在IO
单子。你可以让你的函数返回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
比读者单子(又名功能)为随机生成多一点,这样你就可以轻松地把它改写无在MonadRandom
包:只
randomNums :: RandomGen g => g -> [(Int,Double)]
randomNums = zip [1..] . randoms
,那signuature将不太愉快,如果你有多个娘家的东西用d随机生成器; monad会自动注意分配它们。随着明确的功能,你将不得不一直呼吁split
,这很快就会变得混乱。
感谢您的帮助。这看起来很清楚;但是,我收到错误。什么是'randoms'? 'zip [1 ..]。randoms'我也遇到了错误'randomNums = fmap(zip [1 ..])getRandoms'。什么是'getRandoms'? – turtle 2013-04-28 16:08:02
['randoms ::(RandomGen g,Random a)=> g - > [a]'](http://www.haskell.org/hoogle/?hoogle=randoms)是基础包,你有已经(显然导入了合格的System.Random作为SR',所以它是'SR.randoms')。 ['getRandoms ::(Random a,MonadRandom m)=> m [a]'](http://hackage.haskell.org/packages/archive/MonadRandom/0.1.9/doc/html/Control-Monad-Random -Class.html)来自MonadRandom,你可能需要'cabal install'。 – leftaroundabout 2013-04-28 16:17:02
如果你想要一个纯粹的随机列表,然后使用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
为您提供了一种方式与effectful懒列表来工作,而无需牺牲采用高层次的转换操纵它们的能力。
是'>>>'提示符? – 2013-04-28 16:08:48
@WillNess是的,这应该是一个ghci提示。这只是我从编写黑道的习惯。 – 2013-04-28 16:11:08
这可能会令人困惑。 :) 谢谢。 – 2013-04-28 16:11:53
整数流是正常计数的流(如1,2,3等)还是它可以是任何整数序列? – 2013-04-28 15:37:05
他们真的可以是任何东西,并以任何顺序。字符串,Ints等。我想为此列表中的每个项目创建一个随机浮点数。 – turtle 2013-04-28 15:48:49