[英]Random number generating in haskell
当运行genRandTupe
我不断获得相同的随机数,但是当运行genrandList
, gen
为参数时,每次都会得到一组新的数字。 我该如何解决? 为什么g = newStdGen
生成新的随机数?
import System.Random
import System.IO.Unsafe
type RandTupe = (Int,Int)
genRandTupe :: IO RandTupe
genRandTupe = let [a,b] = genrandList g in return (a,b) where g = newStdGen
genrandList gen = let g = unsafePerformIO gen in take 2 (randomRs (1, 20) g)
gen = newStdGen
genRandTupe
是一个常量应用形式 。 这意味着在任何局部变量let
或where
块memoised。 通常很方便的壮举!
在您的情况下,这意味着列表[a,b]
在整个程序中仅计算一次。 计算方式实际上是非法的( 不要使用unsafePerformIO
!),但这并不重要,因为它只会发生一次。 将这个常量元组包装到IO
并return
,实际上是完全多余的,您也可以写
genRandTupe' :: RandTupe
genRandTupe' = let [a,b] = genrandList g in (a,b)
where g = newStdGen
OTOH,当您在多个单独的位置评估genrandList gen
(不是CAF)时,结果不一定会存储。 取而代之的是,使用unsafePerformIO
不安全地修改全局状态来重新计算该函数(或者可能不会...编译器实际上可以自由地对此进行优化,因为您知道genRandList
应该是纯函数...),因此产生每次都有不同的结果。
当然,正确的做法是远离unsafePerformIO
。 实际上,根本不需要在genRandList
执行IO,因为它已经接受了随机生成器...只需在传递它之前将其与IO绑定即可:
genRandTupe'' :: IO RandTupe
genRandTupe'' = do
g <- newStdGen
let [a,b] = genrandList g
return (a,b)
randListFrom :: RandomGen g => g -> [Int]
randListFrom g = take 2 (randomRs (1, 20) g)
请注意,因为let [a,b] = ...
现在在do
块中,所以它现在在IO
monad中,与genRandTupe''
的CAF genRandTupe''
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.