
Okay, I'm going to give some more stylistic notes.
8. let combined = parseArgs Args
You don't need this one.
Lines 9 - 11 let sep = separateFiles args fl = head (fst sep) showResultsFile fl (snd sep)
Why not: let (f, s) = separateFiles args showResultsFile (head f) s
Lines 19-20 processFile fl flags = mapM dispatch [(flag, fl) | flag <- flags]
Why isn't this on one line? Its not particularly long.
Lines 25-31 dispatch (fl, fn) = do handle <- openFile fl ReadMode contents <- hGetContents handle let cnt = getCounter fn res = cnt contents hClose handle return res
Cleaner is: dispatch (fl, fn) = do contents <- withFile fl ReadMode hGetContents return $ getCounter fn contents However also note that you are defining a function of the form f :: (a, b) -> c rather than the better f :: a -> b -> c Naturally, I see that the reason is that you are calling it from mapM. However, I would define dispatch as a curried function, and then use `curry dispatch` in your mapM. It makes dispatch much cleaner.
Lines 36-44 a bunch of putStrLn
You could also use mapM_ putStrLn [list of string to put out], removing duplicate uses of putStrLn here.