Haskell随机生成

Haskell随机生成,haskell,random,Haskell,Random,有人能描述一下下面的类型构造函数和函数是如何工作的吗 type Rand a = State StdGen a getRandom :: (Random a) => Rand a getRandom = get >>= (\r -> let (a,g) = random r in (put g) >> (return a)) runRand :: Int -> Rand a -> a runRand n r = evalState r $

有人能描述一下下面的类型构造函数和函数是如何工作的吗

type Rand a = State StdGen a  

getRandom :: (Random a) => Rand a
getRandom = get >>= (\r -> let (a,g) = random r in (put g) >> (return a))

runRand :: Int -> Rand a -> a
runRand n r = evalState r $ mkStdGen n

runRandIO :: Rand a -> IO a
runRandIO r = randomIO >>= (\rnd -> return $ runRand rnd r)

getRandoms :: (Random a) => Int -> Rand [a]
getRandoms n = mapM (\_ -> getRandom) [1..n]

让我们从头开始:

type Rand a = State StdGen a
这一行告诉您,
Rand a
State
类型的同义词,其状态由
StdGen
给出,其最终值为
a
类型。这将用于在每个随机数请求之间存储随机数生成器的状态

getRandom
的代码可以转换为do符号:

getRandom :: (Random a) => Rand a
getRandom = do
  r <- get                   -- get the current state of the generator
  let (a,g) = random r in do -- call the function random :: StdGen -> (a, StdGen)
    put g                    -- store the new state of the generator
    return a                 -- return the random number that was generated
runRandIO :: Rand a -> IO a
runRandIO r = do
  rnd <- randomIO        -- generate a new random number using randomIO
  return (runRand rnd r) -- use that number as the initial seed for runRand
最后,
getRandoms
获取一个数字
n
,表示要生成的随机值的数量。它构建一个列表
[1..n]
,并将
getRandom
应用于该列表。请注意,
[1..n]
中的实际值未被使用(您可以知道,因为lambda函数以
\\ u->…
开头)。这个列表只是为了有一些元素数量正确的东西。由于
getRandom
返回一个一元值,因此我们使用
mapM
映射列表,这会导致状态(即
StdGen
)通过对
getRandom

的每个调用正确执行线程。基本思想很简单——要创建伪随机数,需要在函数调用之间保持一些状态。因此类型
Rand a
被定义为意味着“
a
以及随机性所需的状态”

状态是使用存储的。这提供了两个主要操作--
get
put
,这两个操作完全按照它们的声音执行。因此,
getRandom
只需查找当前状态,然后调用
random
函数。此函数返回两个值:随机值和新状态。然后,您只需
放入新状态并包装结果值

runRand
允许您打开给定种子的“随机”值
evalState
允许您在给定初始状态的情况下执行有状态计算(即,类型为
states sa
或在本例中为
Rand a
)的值),然后丢弃最终状态,只给出结果。因此,这允许您使用给定的种子运行
Rand a
,并且只返回结果值。该值的类型可以是
a
,而不是
Rand a
,因为它总是为同一种子提供相同的结果

runRandomIO
除了根据IO中的某个全局状态获取种子外,其他操作都是一样的

getRandoms
只需为
[1..n]
列表中的每个元素调用
getRandoms
,即可获取
Rand a
值的列表(忽略实际数字)