-- verify 1: check that each Ramanujan number is indeed the sum of the cubes -- of each pair of components. Note that this returns the total number of -- failures: there can be more than one failure per line, for example if a -- random made-up test number is fed to the program: "1730 1 1 2 2" will -- generate two failures. module Main where import Text.ParserCombinators.Parsec -- data describing a Ramanujan sum: the Ramanumber, then individual -- components which when cubed and added combine to Ramanumber data Rama = Rama Integer [(Integer,Integer)] deriving Show -- parser for a file containing a bunch of Ramanujan sums: -- this generates a list of Rama objects int_num = do s <- option '+' (oneOf "+-") d <- many1 digit let sgn = if s == '+' then 1 else -1 val = read d return (sgn*val) pair_comp = do oneOf [' ', '\t'] val1 <- int_num oneOf [' '] val2 <- int_num return (val1, val2) rama_line = do sum <- many1 digit pairs <- many1 pair_comp newline return (Rama (read sum) pairs) rama_lines = do lines <- many1 rama_line eof return lines -- check functions chk_one i (j,k) = (i == (j^3 + k^3)) chk_line (Rama i (ps)) = length (filter (/= True) (map (chk_one i) ps)) main = do input <- getContents let val = case parse rama_lines "stdin" input of Left err -> error $ "Input:\n" ++ show input ++ "\nError:\n" ++ show err Right result -> result fails = map chk_line val fstr = show (foldr (+) 0 fails) nstr = show (length fails) putStrLn (fstr ++ " failures out of " ++ nstr ++ " numbers checked")