2014-09-02 9 views
5

Piszę program, który powinien być w stanie symulować wiele instancji próbowania systemu zakładów Martingale z ruletką. Chciałbym, aby main wziął argument podający liczbę testów do wykonania, wykonał test wiele razy, a następnie wydrukował liczbę zwycięstw podzieloną przez całkowitą liczbę testów. Mój problem polega na tym, że zamiast wyświetlać listę Bool, którą mogę filtrować, aby policzyć sukcesy, mam listę IO Bool i nie rozumiem, jak mogę ją przefiltrować.Jak rozpakować dowolną długość listy IO Bool

Oto kod źródłowy:

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

jak mam w moich komentarzach, ja po prostu chcę map (<-) na mojej liście IO Bool, ale jak rozumiem, (<-) w rzeczywistości nie jest to funkcja, ale słowo kluczowe. Każda pomoc będzie bardzo ceniona.

+3

Chcesz ['sequence'] (http://hackage.haskell.org/package/base-4.7.0.1/docs/Control-Monad.html#v:sequence)' :: (Monad m) => [ma] -> m [a] ' – luqui

Odpowiedz

10

map martingale gens poda ci coś w rodzaju [IO Bool]. Następnie można użyć sequence aby go rozpakować:

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

bardziej naturalną alternatywą jest użycie mapM bezpośrednio:

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

czyli można napisać

results <- mapM martingale gens 

Uwaga - nawet po to robi w ten sposób twój kod wydaje się nieco nienaturalny. Widzę pewne zalety struktury, w szczególności dlatego, że martingale' jest czystą funkcją. Jednak posiadanie czegoś typu IO StdGen -> IO Bool wydaje się nieco dziwne.

widzę kilka sposobów, aby poprawić go:

  • make martingale' zwróci sam typ IO i przesunąć wywołanie newStdGen całą drogę w dół do niego
  • zrobić gens korzystanie replicateM zamiast replicate

Możesz uzyskać więcej informacji zwrotnej od numeru http://codereview.stackexchange.com.

+0

Dziękuję bardzo! Nie wiedziałem o tej funkcji i nie wiedziałem, że istnieje również kodereview. – anthonybrice

+0

Powinieneś rozejrzeć się po funkcjach w Control.Monad, aby dowiedzieć się, jakie operacje generyczne są dostępne w typach monadycznych, takich jak 'IO': http://hackage.haskell.org/package/base-4.7.0.1/docs/Control -Monad.html –