Haskell函数生成随机数,使每次的数字与以前的数字不同

  • 本文关键字:数字 函数 随机数 Haskell haskell random
  • 更新时间 :
  • 英文 :


我想要一个随机生成的6位数。可以保证,我调用这个函数的次数永远不会超过1000次。该函数应该能够在每次我调用它时返回不同的号码。

我想像nextRandom一样调用这个函数,而不需要任何参数。哈斯克尔有适合我的图书馆吗?我养不住一粒种子。Haskell可以使用当前时间作为seed

更新:问题的上下文。

我正在生成一个图(点格式),我想确保所有顶点都有不同的标签。我可以把生成时间作为标签来实现,但我被通过生成随机数来实现的想法所吸引。

纯函数(如nextRandom,没有参数)类似于数学函数。在每次调用中,它们使用相同的参数生成相同的结果。

所以你想要的是不可能的,因为

  • 你期望的是随机数
  • 您希望函数具有某种内存,可以知道哪些数字已经生成

只需按照haskell的方式,将种子或随机生成器传递给函数,或者使用monad。如果有帮助,您可以提前创建1000个数字,然后从列表中检索它们。

不能有一个每次都返回不同数字的纯函数。它的输出取决于它以前的调用,而不仅仅取决于它的参数。但是,您可以创建一个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使用了一个简单的策略——如果集合中已经存在新号码,则重试生成新号码。只要碰撞次数较低,这种方法就可以很好地工作。

这并不是你想要的,但如果你只需要一个没有替换例程的通用采样,你可以使用我为另一个关于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]

这里可能有助于了解您所询问的函数将被使用的上下文。我不是专家,但这样的东西能帮你吗?

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

最新更新