Author Topic: hparse -- my first hs program  (Read 1694 times)

0 Members and 1 Guest are viewing this topic.

Offline mar77a

  • Global Moderator
  • Veteran
  • *****
  • Posts: 1295
  • mad
    • random stuffs
hparse -- my first hs program
« on: June 13, 2008, 01:06:35 pm »
I started learning Haskell a couple of months ago, quit, then re-started two or three weeks ago, determined to get a decent amount of knowledge. I have to admit I'm fascinated by now...so, here's my first attempt at a real-world useful program: a kill-log parser.

Windows users: just run hparse.exe <kill-logs-dir>
Linux users: you'll need to compile using ghc --make hparse.hs -o hparse (you'll need GHC, the haskell compiler)

Here's the source for anyone who is interested in what a functional programming app looks like:

Code: [Select]
import Data.List
import System.Directory
import System.Environment

-- basic endl
endl = "\n"

-- checks if the given string matches *.txt
isLog :: String -> Bool
isLog log = isSuffixOf ".txt" log

-- gets logs from a directory
getLogs :: String -> IO [String]
getLogs cwd = do
    files <- getDirectoryContents cwd
    return $ filter isLog files

-- sorts & groups all elements together then counts
listGroupCount :: (Ord a) => [a] -> [(a, Int)]
listGroupCount xs = map (\xs -> (head xs, length xs)) ((group . sort) xs)

-- splits logs into a three-tuple with the form (killer,victim,weapon)
logSplit :: FilePath -> IO [(String, String, String)]
logSplit logName = do
    raw <- readFile logName
    return . logSplit' . tail . lines $ raw

logSplit' :: [a] -> [(a,a,a)]
logSplit' [] = []
logSplit' (a:b:c:d:xs) = (b,c,d) : logSplit' xs
logSplit' _ = error "Corrupt log"

-- first message printed
printParsing :: [String] -> FilePath -> IO ()
printParsing logs dir = putStrLn $ "Parsing: " ++ (show n) ++ " log" ++ xs ++ " found in " ++ dir ++ endl
    where n = length logs; xs = if n > 1 || n == 0 then "s" else ""

-- prettifies output of collected stats
printPretty :: [(String, Int)] -> IO ()
printPretty = (putStrLn . concat . printPretty')

printPretty' :: (Show t) => [(String, t)] -> [String]
printPretty' [] = []
printPretty' (x:xs) = (\(name,count) -> name ++ " => " ++ (show count) ++ endl) x : printPretty' xs

usage = error "Usage: hparse <dir>\n\t<dir>: Directory where the kill-logs are stored"

-- main
main :: IO ()
main = do
    args <- getArgs
    let dir = if null args then usage else head args
    logs <- getLogs dir
    printParsing logs dir
    logSp <- mapM logSplit logs
    let allData = foldr (++) [] logSp
    --let killers = map (\(b,c,d) -> b) allData
    --let victims = map (\(b,c,d) -> c) allData
    let weapons = map (\(b,c,d) -> d) allData
    printPretty $ listGroupCount weapons
    --printPretty $ listGroupCount killers
    --printPretty $ listGroupCount victims

As you can see (-- is the one-line comment operator in hs), the code can be extended to search for top killers, top victims, etc, but as usual, I lost interest in coding such features which in turn I leave for anyone who has the will to add them.

Attached: the source & the windows binary in the zip.

Offline jrgp

  • Administrator
  • Flamebow Warrior
  • *****
  • Posts: 5037
Re: hparse -- my first hs program
« Reply #1 on: June 13, 2008, 01:34:48 pm »
Looks pretty interesting, but does it handle the Soldat logging bugs?
There are other worlds than these

Offline Hair|Trigger

  • Veteran
  • *****
  • Posts: 1595
  • HT|
Re: hparse -- my first hs program
« Reply #2 on: June 14, 2008, 11:39:04 pm »
Much too complicated for my liking :Z

But it's just a soldat kill log right?

Player since late 2007