Skip to content

Instantly share code, notes, and snippets.

@commandodev
Forked from petermarks/Automata.hs
Created November 14, 2011 12:00
Show Gist options
  • Save commandodev/1363807 to your computer and use it in GitHub Desktop.
Save commandodev/1363807 to your computer and use it in GitHub Desktop.
Automata
module Automata where
import Prelude hiding (map, head, foldl, take)
import qualified Prelude as P
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as C
import Data.ByteString.Internal (c2w)
import qualified Data.Map as M
import Data.List (sort)
import Data.Tuple
import System.Environment
import Data.Enumerator hiding (foldl)
import Data.Enumerator.List
import qualified Data.Enumerator.Binary as EB
-- Data Types
data Entry = Entry {
date :: BS.ByteString,
host :: BS.ByteString,
program :: BS.ByteString,
message :: BS.ByteString
} deriving Show
type Summary = M.Map BS.ByteString Int
-- Enumerator
filelines :: FilePath -> Enumerator BS.ByteString IO a
filelines fname = EB.enumFile fname $= EB.splitWhen (==(c2w '\n'))
-- Iteratees
count :: Monad m => Iteratee BS.ByteString m Int
count = (fold (flip $ const (+1)) 0)
summary :: Monad m => Iteratee BS.ByteString m Summary
summary = fold op M.empty
where op :: Summary -> BS.ByteString -> Summary
op sumMap line =
let e = parseEntry line
in M.insertWith' (+) (program e) 1 sumMap
-- Utils
parseEntry :: BS.ByteString -> Entry
parseEntry s = Entry d h p m
where d1:d2:d3:h:p':ms = C.words s
d = C.unwords [d1,d2,d3]
p = BS.init p'
m = C.unwords ms
top10 :: Summary -> [(Int, BS.ByteString)]
top10 = P.take 10 . P.reverse . sort . P.map swap . M.toList
processFile :: Enumerator BS.ByteString IO (Int, Summary) -> IO (Int, [(Int, BS.ByteString)])
processFile enum = do
(i, sum) <- run_ $ enum $$ EB.zip count summary
return (i, top10 sum)
main = do
fname <- getArgs >>= return . P.head
print =<< (processFile $ filelines fname)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment