如何解压缩任意长度的IO Bool列表

ant*_*ice 5 io haskell

我正在编写一个程序,应该可以模拟许多用轮盘赌尝试鞅投注系统的实例.我想main提出一个参数,给出要执行的测试次数,多次执行测试,然后打印获胜次数除以测试总次数.我的问题是,我没有最终列出Bool我可以过滤来计算成功的列表,而是有一个列表,IO Bool我不明白我如何过滤它.

这是源代码:

-- file: Martingale.hs
-- a program to simulate the martingale doubling system

import System.Random (randomR, newStdGen, StdGen)
import System.Environment (getArgs)

red = [1,3,5,7,9,12,14,16,18,19,21,23,25,27,30,32,34,36]

martingale :: IO StdGen -> IO Bool
martingale ioGen = do
  gen <- ioGen
  return $ martingale' 1 0 gen

martingale' :: Real a => a -> a -> StdGen -> Bool
martingale' bet acc gen
  | acc >= 5     = True
  | acc <= -100  = False
  | otherwise    = do
    let (randNumber, newGen) = randomR (0,37) gen :: (Int, StdGen)
    if randNumber `elem` red
      then martingale' 1 (acc + bet) newGen
      else martingale' (bet * 2) (acc - bet) newGen

main :: IO ()
main = do
  args <- getArgs
  let iters = read $ head args
      gens = replicate iters newStdGen
      results = map martingale gens
      --results = map (<-) results
  print "THIS IS A STUB"
Run Code Online (Sandbox Code Playgroud)

就像我在评论中一样,我基本上想要映射(<-)我的列表IO Bool,但据我所知,它(<-)实际上不是一个函数而是一个关键字.任何帮助将不胜感激.

GS *_*ica 10

map martingale gens会给你一些类型的东西[IO Bool].然后您可以使用sequence它来解压缩它:

sequence :: Monad m => [m a] -> m [a]
Run Code Online (Sandbox Code Playgroud)

更自然的替代方案是mapM直接使用:

mapM :: Monad m => (a -> m b) -> [a] -> m [b]
Run Code Online (Sandbox Code Playgroud)

即你可以写

results <- mapM martingale gens
Run Code Online (Sandbox Code Playgroud)

注意 - 即使这样做,您的代码也会感觉有点不自然.我可以看到结构的一些优点,特别是因为它martingale'是一个纯函数.但是有一些类型IO StdGen -> IO Bool似乎有点奇怪.

我可以看到几种方法来改进它:

  • 让自己martingale'返回一个IO类型并将newStdGen调用一直推入其中
  • 使gens利用replicateM而不是replicate

您可能需要访问http://codereview.stackexchange.com以获得更全面的反馈.