我想要一个随机生成的6位数字。保证我永远不会将此功能调用超过1000次。每次调用它时,该函数都应该能够返回不同的数字。
我想在没有任何参数的情况下将此函数称为nextRandom
。 Haskell中有没有适合我的库?我不能保持种子。 Haskell可以将当前时间用作seed
。
更新:问题的背景。
我正在生成图形(点格式),我想确保所有顶点都有不同的标签。我可以将生成时间作为标签附加,但我通过生成随机数来实现这一点。
答案 0 :(得分:7)
纯函数(如nextRandom
,没有参数)就像数学函数。在每次调用时,他们使用相同的参数产生相同的结果。
所以你要求它是不可能的,因为
只需使用haskell方式,将种子或随机生成器传递给函数,或使用monad。如果有帮助,您可以提前创建1000个数字,然后从列表中检索它们。
答案 1 :(得分:6)
您不能拥有每次都返回不同数字的纯函数。它的输出取决于它以前的调用,而不仅仅依赖于它的参数。但是你可以创建一个带有到目前为止生成的数字集的monad,然后重试生成一个随机数,直到它找到一个到目前为止尚未生成的数字。对于以下示例,我使用了MonadRandom包。
import Control.Monad
import Control.Monad.Random
import Control.Monad.State
import Data.IntSet (IntSet)
import qualified Data.IntSet as IS
import System.Random (getStdGen)
type RandDistinct g a = StateT IntSet (Rand g) a
evalDistinct :: RandomGen g => RandDistinct g a -> g -> a
evalDistinct k = evalRand (evalStateT k IS.empty)
上述类型使用StateT
来增强随机数生成器,以便记住到目前为止生成的数字集。当我们想要评估这个monad中的计算时,我们从一个空集开始,用evalRand
计算内部计算。
现在我们可以编写一个每次都返回一个不同数字的函数:
nextDistinct :: RandomGen g => (Int,Int) -> RandDistinct g Int
nextDistinct range = loop
where
-- Loop until we find a number not in the set
loop = do
set <- get
r <- getRandomR range
if IS.member r set
then loop -- repeat
else put (IS.insert r set) >> return r
并测试它是如何工作的:
main = getStdGen >>= print . evalDistinct (replicateM 50 $ nextDistinct (10, 99))
请注意nextDistinct
使用简单策略 - 如果集合中已存在新数字,则重试生成新数字。只要碰撞次数很少,这种方法就可以正常工作。
答案 2 :(得分:1)
这里可能有助于更多地使用您要询问的函数的上下文。我远非专家,但是这样的事情会帮助你吗?
import Control.Monad.Random
rnd :: (RandomGen g) => Rand g Int
rnd = getRandomR (100000,999999)
main = do
putStr "\nPlease type 'nextRandom' or 'quit':\n> "
mainLoop [] where
mainLoop memory = do
command <- getLine
case command of
"nextRandom" -> do next <- randomLoop memory
putStr (show next ++ "\n> ")
mainLoop (next:memory)
"quit" -> return ()
otherwise -> putStr "\n> "
randomLoop memory = do
value <- evalRandIO rnd
if elem value memory
then randomLoop memory
else return value
答案 3 :(得分:1)
不完全是您正在寻找的,但如果您只需要一个通用的采样 - 无需更换例程,您可以使用类似this example module之类的东西,我在SO上提出另一个问题。
只需提前生成许多不同的六位数字,并在任何地方使用它们。例如:
import System.Random.MWC
import Sample
main :: IO ()
main = do
ns <- withSystemRandom . asGenIO $ \gen -> sample [100000..999999] 10 gen
print ns
-- [754056,765889,795475,389702,120426,740641,556446,490338,534738,213852]