1

我正在学习 Haskell。 Haskell 中大量骰子掷骰的平均值 我应该如何让下面的代码与多个骰子一起工作,比如 8 个骰子)而不是重复创建让掷骰子……3,4,5……等等……

module Dice where
import System.Random
import Data.List

dice = do
    g <- getStdGen
    b <- newStdGen
    let trials = 1000
    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
4

3 回答 3

4

System.Random模块提供了一些基本的原语,但(在我看来)它缺乏适当的一元接口。更准确地说,它提供了一个基于 IO 的单子接口,但缺少一个基于状态的单子接口。不过,后者很容易定义

无论如何,如果想坚持使用 IO 和标准生成器,可以这样写:

-- (untested code)

rollDie :: Int -> IO Int
rollDie n = randomIO (1,n) -- implicitly uses the global generator

rollManyDice :: Int -> Int -> IO [Int]
rollManyDice howMany n = replicateM howMany (rollDie n)

main :: IO ()
main = do
   dice <- rollManyDice 20 6
   putStrLn $ "Here's 20 6-sides dice : " ++ show dice

wherereplicateM执行howMany一次单子动作,将所有结果收集到一个列表中。monad 在这里IO,但它可以是任何东西。

这是一种很好很简单的方法,但是IO上面的类型有点太多了,阻止了我们rollDie从非 IO 代码中调用。基于-State的解决方案不会有这个限制

type R a = State StdGen a

rollDie :: Int -> R Int
rollDie n = state $ randomR (1,n) -- uses the generator inside the State monad

rollManyDice :: Int -> Int -> R [Int]
rollManyDice howMany n = replicateM howMany (rollDie n)

main :: IO ()
main = do
   g <- getStdGen
   let dice = evalState (rollManyDice 20 6) g
   putStrLn $ "Here's 20 6-sides dice : " ++ show dice
于 2018-06-23T09:09:17.443 回答
0

目前,按照公式,您只需将 k*N个单独的骰子汇总并除以 N,其中 k 是您要“同时”滚动的骰子数量,N 次试验。在一次掷骰中将所有骰子相加然后将所有掷骰相加与将所有骰子总体相加相同。

如果你想让它变得复杂,那么,让单个 multiroll 指定长度的随机值列表,对其求和(sum当 k 不太大时,即使没有优化,你也可以使用 plain),计算结果的平均值。

于 2018-06-23T05:41:24.513 回答
0
module Dice where
import System.Random
import Data.List
import Control.Applicative
import Control.Monad

rollDie :: Int -> IO Int
rollDie n = randomRIO (1,n)

rollManyDice :: Int -> Int -> IO [Int]
rollManyDice howMany n = replicateM howMany (rollDie n)

dice2 = do
    dice <- rollManyDice 8 6
    putStrLn $ "Here's 20 -6 sided dice: " ++show dice
于 2018-06-23T11:08:00.367 回答