Haskell Quiz/Probable Iterations/Solution Dolio

From HaskellWiki
Jump to: navigation, search

This quiz was pretty simple. The list monad makes generation of the test cases simple, and the writer monad is handy for capturing potential output for each line. I used a DList for the writer accumulator to avoid repeated copying.

module Main where

import Data.DList

import Control.Monad.Writer.Lazy

import System.Environment
import System.Exit
import Control.Monad

import Text.Printf

die = [1..6]

check :: ([Int] -> Bool) -> (Int, [Int]) -> Writer (DList String) Bool
check p (line, roll) = do tell $ if b then singleton hit else singleton noHit ; return b
 b = p roll
 noHit = printf "%12d  %s" line (show roll)
 hit   = noHit ++ "  <=="

sample :: Int -> Int -> (Int, (Int, DList String))
sample i j = (length l, runWriter . liftM length . filterM (check p) $ zip [1..] l)
 p l = length (filter (==5) l) >= j
 l = replicateM i die

chop :: [a] -> [a]
chop [] = []
chop (x:xs) = x : chop (drop 49999 xs)

main = do (v,s,i,j) <- processArgs
          let (total, (selected, out)) = sample i j
          if v
           then mapM_ putStrLn $ toList out
           else when s . mapM_ putStrLn . chop $ toList out
          putStrLn ""
          putStr "Number of desirable outcomes is "
          print selected
          putStr "Number of possible outcomes is "
          print total
          putStrLn ""
          putStr "Probability is "
          print $ fromIntegral selected / fromIntegral total

processArgs = do l <- getArgs
                 case l of
                      [i,j]        -> return (False, False, read i, read j)
                      ["-v", i, j] -> return (True, False, read i, read j)
                      ["-s", i, j] -> return (False, True, read i, read j)
                      _            -> do putStrLn "Unrecognized arguments."