迭代和getStdRandom

问题描述 投票:1回答:1

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

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的懒惰。

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

haskell random
1个回答
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得到恒定的v0; v1中随机序列的第一个元素(不是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
© www.soinside.com 2019 - 2024. All rights reserved.