迭代并获取stStRandom

时间:2018-09-16 16:04:50

标签: haskell random

我有以下代码(试图模拟高斯随机游动):

import System.Random
import Control.Applicative

getStdNormal :: StdGen -> (Float,StdGen)
getStdNormal g = let l = drop 1 . take 49 $ iterate (\(_,g') -> random g') (0,g) in
                ((/ 2) . (+ (-24)) . sum . map fst $ l, snd . last $ l)

mphi = getStdRandom getStdNormal

l1 = setStdGen (mkStdGen 20180916) >> (sequence . take 10 $
                iterate (\s -> (\a -> \b ->  b) <$> s <*> mphi) (return 0))

l2 = setStdGen (mkStdGen 20180916) >> (sequence . take 10 $
                iterate (\s -> (\a -> \b -> a + b) <$> s <*> mphi) (return 0))
正如我所期望的,

l1被评估为(显然是正常的)随机值列表:

[0.0,1.1155739,-0.24667645,0.7793722,-0.18391132,0.23517609,-0.80208874,-1.5305595,-0.28670216,0.53894806]

但是,l2的表现与我的预期相去甚远。该列表显然不是l1部分和的序列,并且极不可能具有标准的正态差异:

[0.0,1.1155739,0.55951977,0.22015285,-2.0858078,0.6170025,-5.20298,0.3877325,1.410594,0.8647003]

(请注意,前两个成员是正确的。)实际上,尽管我倾向于指责l2中的懒惰,但我无法解释mphi中数字的来源。 / p>

为什么代码不能按预期工作?非常感谢!

1 个答案:

答案 0 :(得分:1)

以下是iterate (\s -> (\a b -> b) <$> s <*> mphi) (return 0)的前几个元素:

return 0
(\a b -> b) <$> return 0 <*> mphi
(\a b -> b) <$> ((\a b -> b) <$> return 0 <*> mphi) <*> mphi
(\a b -> b) <$> ((\a b -> b) <$> ((\a b -> b) <$> return 0 <*> mphi) <*> mphi) <*> mphi

对这些序列进行排序时,会得到以下结果:

do
    v0 <- return 0
    v1 <- (\a b -> b) <$> return 0 <*> mphi
    v2 <- (\a b -> b) <$> ((\a b -> b) <$> return 0 <*> mphi) <*> mphi
    v3 <- (\a b -> b) <$> ((\a b -> b) <$> ((\a b -> b) <$> return 0 <*> mphi) <*> mphi) <*> mphi
    return [v0, v1, v2, v3]

请特别注意,这些行之间不会重置随机种子,并且\a b -> b抛出的内容是结果值,而不是 IO操作。这意味着我们在0中得到了常量v0v1中随机序列的第一个元素(不是v0!); v2中随机序列的第三个元素(完全跳过第二个元素)(这可能是您想要的,但只是偶然...); v3中随机序列的第六个元素(不是v5!并完全跳过序列的第四和第五个元素);依此类推,将三角形数最多,扔掉我们生成的随机数中的最多

您几乎可以肯定想要的是

do
    v0 <- mphi
    v1 <- mphi
    v2 <- mphi
    v3 <- mphi
    return [v0, v1, v2, v3]

可以通过使用repeat mphi而不是iterate (\s -> ...) (return 0)来实现。这使我们到达:

sequence . take 10 $ repeat mphi

习惯上,然后将take 10 (repeat mphi)更改为replicate 10 mphi,然后将sequence (replicate 10 mphi)更改为replicateM 10 mphi

类似的注释也适用于您的求和版本:结果列表的元素n已生成n个随机数(与先前使用的任何一个都不相同,用于结果列表中较早的总和)并将它们相加。也许这就是您想要的,但是我怀疑您真正想要的只是:

scanl (+) 0 <$> replicateM 10 mphi