我想要一个随机生成的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