改进代码以生成分发

Ash*_*Ash 5 statistics haskell

我是Haskell的新手,我想知道如何使这段代码变得更加高效和整洁.这似乎不必要地长而不整洁.

我的脚本生成10个平均10个硬币翻转的列表.

import Data.List
import System.Random

type Rand a = StdGen -> Maybe (a,StdGen)

output = do
    gen <- newStdGen
    return $ distBernoulli 10 10 gen

distBernoulli :: Int -> Int -> StdGen -> [Double]
distBernoulli m n gen = [fromIntegral (sum x) / fromIntegral (length x) | x <- lst]
    where lst = splitList (randomList (n*m) gen) n

splitList :: [Int] -> Int -> [[Int]]
splitList [] n = []
splitList lst n = take n lst : splitList (drop n lst) n

randomList :: Int -> StdGen -> [Int]
randomList n = take n . unfoldr trialBernoulli

trialBernoulli :: Rand Int
trialBernoulli gen = Just ((2*x)-1,y)
                 where (x,y) = randomR (0,1) gen
Run Code Online (Sandbox Code Playgroud)

任何帮助将不胜感激,谢谢.

Tra*_*own 3

我会以稍微不同的方式解决这个问题。首先,我定义一个函数,它可以从伯努利分布中以成功概率对翻转进行无限采样p:

flips :: Double -> StdGen -> [Bool]
flips p = map (< p) . randoms
Run Code Online (Sandbox Code Playgroud)

然后我会写distBernoulli如下:

distBernoulli :: Int -> Int -> StdGen -> [Double]
distBernoulli m n = take m . map avg . splitEvery n . map val . flips 0.5
  where
    val True = 1
    val False = -1
    avg = (/ fromIntegral n) . sum
Run Code Online (Sandbox Code Playgroud)

我认为这符合您的定义distBernoulli:

*Main> distBernoulli 10 10 $ mkStdGen 0
[-0.2,0.4,0.4,0.0,0.0,0.2,0.0,0.6,0.2,0.0]
Run Code Online (Sandbox Code Playgroud)

(请注意,我使用的是splitEvery方便的拆分包,因此您必须安装该包并添加import Data.List.Split (splitEvery)到您的导入中。)

这种方法稍微更通用,我认为更简洁,但实际上主要的区别在于我使用的是randomsand splitEvery。