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
值的列表(忽略实际数字)