Haskell函数生成随机数,使得每次数字与前一个数字不同

Dil*_*war 3 random haskell

我想要一个随机生成的6位数字.保证我永远不会将此功能调用超过1000次.每次调用它时,该函数应该能够返回不同的数字.

我想在nextRandom没有任何争论的情况下调用此函数.Haskell中有没有适合我的库?我不能保持种子.Haskell可以使用当前时间seed.

更新:问题的背景.

我正在生成一个图形(点格式),我想确保所有顶点都有不同的标签.我可以将生成时间作为标签附加,但我通过生成随机数来实现这一点.

Kar*_*ath 7

纯函数(如nextRandom没有参数)就像数学函数.在每次调用时,它们使用相同的参数产生相同的结果.

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

  • 你期望随机数.
  • 你希望函数有某种内存来知道哪些数字已经生成.

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


Pet*_*lák 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)
Run Code Online (Sandbox Code Playgroud)

上述类型用于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
Run Code Online (Sandbox Code Playgroud)

并测试它是如何工作的:

main = getStdGen >>= print . evalDistinct (replicateM 50 $ nextDistinct (10, 99))
Run Code Online (Sandbox Code Playgroud)

请注意,nextDistinct使用简单策略 - 如果集合中已存在新数字,则重试生成新数字.只要碰撞次数很少,这就可以正常工作.