我有以下代码(试图模拟高斯随机游走):
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
的懒惰。
为什么代码不按预期工作?非常感谢!
以下是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