Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I unpack an arbitrary length list of IO Bool

Tags:

io

haskell

I'm writing a program that should be able to simulate many instances of trying the martingale betting system with roulette. I would like main to take an argument giving the number of tests to perform, perform the test that many times, and then print the number of wins divided by the total number of tests. My problem is that instead of ending up with a list of Bool that I could filter over to count successes, I have a list of IO Bool and I don't understand how I can filter over that.

Here's the source code:

-- 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"

Like I have in my comments, I basically want to map (<-) over my list of IO Bool, but as I understand it, (<-) isn't actually a function but a keyword. Any help would be greatly appreciated.

like image 727
imperfectgrist Avatar asked Sep 02 '14 05:09

imperfectgrist


1 Answers

map martingale gens will give you something of type [IO Bool]. You can then use sequence to unpack it:

sequence :: Monad m => [m a] -> m [a]

A more natural alternative is to use mapM directly:

mapM :: Monad m => (a -> m b) -> [a] -> m [b]

i.e. you can write

results <- mapM martingale gens

Note - even after doing it this way, your code feels a bit unnatural. I can see some advantages to the structure, in particular because martingale' is a pure function. However having something of type IO StdGen -> IO Bool seems a bit odd.

I can see a couple of ways to improve it:

  • make martingale' return an IO type itself and push the newStdGen call all the way down into it
  • make gens use replicateM rather than replicate

You may want to head over to http://codereview.stackexchange.com for more comprehensive feedback.

like image 135
GS - Apologise to Monica Avatar answered Oct 21 '22 12:10

GS - Apologise to Monica