有没有办法在 haskell 中泛化多个生成器和随机数
Is there a way to generalise multiple generators and randoms in haskell
我正在学习 Haskell。
Average of large number of Dice Rolls in Haskell
我该如何使下面的代码与多个骰子一起工作,比如 8 个骰子)而不是重复创建 let rolls..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
目前的公式是,你只需要将k*N 个人 掷骰数除以N,其中k是你要掷的骰子数量"simultaneously", N 次试验。在一次掷骰中对所有骰子求和然后对所有掷骰求和与对所有骰子整体求和相同。
如果你想让它复杂一点,好吧,让单个 multiroll 成为一个指定长度的随机值列表,对它求和(你可以使用普通的 sum
即使当 k 不太大时没有优化),计算结果的平均值。
System.Random
模块提供了一些基本的原语,但(在我看来)它缺少适当的单子接口。更准确地说,它提供了一个基于 IO 的单子接口,但缺少一个基于状态的单子接口。然而,后者是 easy to define 。
无论如何,如果想坚持使用 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
其中 replicateM
执行 howMany
次单子操作,将所有结果收集在一个列表中。这里的 monad 是 IO
,但它可以是任何东西。
这是一个很好的简单方法,但是上面的IO
类型有点太多了,妨碍了我们从非IO代码中调用rollDie
。基于 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
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
我正在学习 Haskell。 Average of large number of Dice Rolls in Haskell 我该如何使下面的代码与多个骰子一起工作,比如 8 个骰子)而不是重复创建 let rolls..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
目前的公式是,你只需要将k*N 个人 掷骰数除以N,其中k是你要掷的骰子数量"simultaneously", N 次试验。在一次掷骰中对所有骰子求和然后对所有掷骰求和与对所有骰子整体求和相同。
如果你想让它复杂一点,好吧,让单个 multiroll 成为一个指定长度的随机值列表,对它求和(你可以使用普通的 sum
即使当 k 不太大时没有优化),计算结果的平均值。
System.Random
模块提供了一些基本的原语,但(在我看来)它缺少适当的单子接口。更准确地说,它提供了一个基于 IO 的单子接口,但缺少一个基于状态的单子接口。然而,后者是 easy to define 。
无论如何,如果想坚持使用 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
其中 replicateM
执行 howMany
次单子操作,将所有结果收集在一个列表中。这里的 monad 是 IO
,但它可以是任何东西。
这是一个很好的简单方法,但是上面的IO
类型有点太多了,妨碍了我们从非IO代码中调用rollDie
。基于 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
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