Haskell中大量掷骰子的平均值

Haskell中大量掷骰子的平均值,haskell,random,functional-programming,Haskell,Random,Functional Programming,为了更好地学习Haskell,我正在尝试编写一个程序,显示2个骰子的平均值,滚动X次数。这在C、Java、Python中相当简单。。。但我被困在哈斯克尔。以下是一个天真的尝试: import System.Random main = do g <- getStdGen let trials = 10000000 let rolls = take trials (randomRs (2, 12) g :: [Int]) let average = div (

为了更好地学习Haskell,我正在尝试编写一个程序,显示2个骰子的平均值,滚动X次数。这在C、Java、Python中相当简单。。。但我被困在哈斯克尔。以下是一个天真的尝试:

import System.Random

main = do
    g <- getStdGen
    let trials = 10000000
    let rolls = take trials (randomRs (2, 12) g :: [Int])
    let average = div (sum rolls) trials
    print average
一定有更好的方法来编写这个程序。在C、Java和Python版本中,这是一项简单的任务。我看过这篇文章(理解了大约75%的内容),但当我将代码适应这种情况时,对
R[Int]
序列求和是不起作用的(我不知道如何“展开”这个[Int])。我做错了什么?正确的方法是什么?如何在Haskell中获得随机数启示


编辑:除所选答案外,正如rtperson在下面指出的,2个骰子的建模是不正确的;它实际上应该是从1到6的两个独立滚动的总和。

sum
对长列表求和没有好处,它在线性空间中运行。尝试此严格版本的
sum

sum' = foldl' (+) 0
foldl'
Data.List
中定义


编辑更多信息可在中找到。

事实上,此处的概率模型不正确。在编写代码时,同样有可能得到2到12。但这不是骰子的工作原理。在12种可能的结果中,只有一种方法可以得到2(通过1和1)和12(通过6和6)。但是有6种方法可以得到7(1-6,2-5,3-4,4-3,5-2,6-1)。模拟两个骰子的掷骰,而不是一次2到12的机会,将给出正确的预期值7

然而——这是你的头发真正开始卷曲的地方——你不能简单地做如下事情:

let rolls1 = take trials (randomRs (1, 6) g :: [Int])
let rolls2 = take trials (randomRs (1, 6) g :: [Int])
因为rolls1和rolls2将产生相同的结果

*Main> let rolls = zip rolls1 rolls2
*Main> take 10 rolls
[(3,3),(4,4),(5,5),(3,3),(5,5),(1,1),(3,3),(1,1),(3,3),(3,3)]
因此,您的结果将始终是均匀的,因此仍然是错误的答案

要获得两个明显随机的列表,您必须生成一个新的StdGen:

import System.Random
import Data.List

main = do
    g <- getStdGen
    b <- newStdGen   -- calls "split" on the global generator
    let trials = 10000000
    let rolls1 = take trials (randomRs (1, 6) g :: [Int])
    let rolls2 = take trials (randomRs (1, 6) b :: [Int])
    let rolls = zipWith (+) rolls1 rolls2
    let average = div (foldl' (+) 0 rolls) trials
    print average
导入系统。随机
导入数据。列表
main=do

g结果是6,SCNR:)实际上,两个骰子之和的期望值是(1+2+3+4+5+6)/6*2=7。这个练习的重点是学习如何用这种语言编程,而不是统计方面。呵呵:)在计算一个骰子的期望值后出现了舍入错误:)在链接的帖子中,展开
R[Int]
的方法是使用
runRandom
函数。谢谢,我已经很久没有做功能性的东西了。另一方面,我想知道,如果程序分析得出计算结果将被评估,是否有可能使
sum
从懒惰转换为严格。@benson:是的,有严格性分析这样的东西,但我不确定为什么在这种情况下它不起作用。@n.m.严格性分析只有在启用优化时才能完成。使用
ghc-O1
或更高版本编译是可行的。@n.m.默认情况下没有优化。当然,您可以只查看单个列表中的对,而不必获得两个Gen,这可能稍微干净一些:-)@sclv-True。我是从State monad Wikibooks文章()上的“clumsyRollDice”函数向后思考的,它在每次滚动后创建一个新的StdGen。
import System.Random
import Data.List

main = do
    g <- getStdGen
    b <- newStdGen   -- calls "split" on the global generator
    let trials = 10000000
    let rolls1 = take trials (randomRs (1, 6) g :: [Int])
    let rolls2 = take trials (randomRs (1, 6) b :: [Int])
    let rolls = zipWith (+) rolls1 rolls2
    let average = div (foldl' (+) 0 rolls) trials
    print average