在保留种子的同时生成随机字符列表

时间:2016-01-10 13:59:47

标签: haskell

我的目标是编写一个函数,根据种子生成给定长度的随机字符串(字母数字)。重要的是,结果不仅是字符串,还包括新种子。

我知道我可以通过使用take on randomRS获得一个字符串,但问题是我之后无法检索种子

generate :: StdGen -> String -> (String, StdGen) 

我能够为一个角色编写它,虽然我无法获得允许字母和数字的范围

generateRandomCharacter gen = randomR ('a','z') gen

3 个答案:

答案 0 :(得分:3)

最好的技巧是使用“拆分”:

class RandomGen g where
    split :: g -> (g,g)
    -- Other functions as well.

将您的随机生成器分成两部分。使用其中一个结果生成随机字符串,并返回另一个结果。

从你的问题不清楚字符串应该是多长时间:大概它应该与输入字符串的长度相同。如果是这样,那么以Int长度作为参数将是更好的风格。

你还说你还没有弄清楚如何从一个更复杂的范围中选择('a','z')。您需要设置一个候选项目的数组(或更好的矢量)并从中选择一个。您可以使用列表,但这意味着您每次都会遍历列表。

答案 1 :(得分:3)

保罗约翰逊的种子分裂方法当然是合理的,但由于你生成了一个已知长度的字符串,另一个好的选择是在随机monad中使用replicateM

generateR :: (MonadRandom m, Random a) => Int -> (a, a) -> m [a]
generateR len range = replicateM len (getRandomR range)

答案 2 :(得分:1)

一种方法是将您感兴趣的可用字符定义为数组,然后从数组中随机选择字符。

randomEl :: RandomGen g => [a] -> g -> (a, g)
randomEl xs g -> (g', xs !! r) 
  where (r, g') = randomR (0, length xs - 1) g

randomAlphaNum :: RandomGen g => g -> (Char, g)
randomAlphaNum = randomEl (['0'..'9'] ++ ['a'..'z'])

接下来构建字符串应该非常简单......例如,Prelude中定义了iterate

generate :: RandomGen g => Int -> g -> (String, g)
generate n g = (map fst iterations, (snd . last) iterations)
  where iterations = (take n . iterate (randomAlphaNum . snd)) (randomAlphaNum g)