Hello all,

I'm relatively new to Haskell and trying to solve some online judge's
problems in it.
One of the problems is to say if a given sentence is a tautogram or not.
A tautogram is just a sentence with all the words starting with the same letter.

My first try (solution is ok) was to do it as haskeller as possible,
trying to overcome my imperative mind.
But it did bad at performance (0.30 secs of runtime, 4.6 mb of memory):

-- code start
import Data.Char (toLower)

main = getContents >>=  mapM_ (putStrLn . toStr . isTautogram . words)
. takeWhile (/= "*") . lines

toStr :: Bool -> [Char]
toStr True = "Y"
toStr False = "N"

isTautogram :: [[Char]] -> Bool
isTautogram (x:[]) = True
isTautogram (x:xs) = all ((== firstChar) . toLower . head) xs
    where firstChar = toLower . head $ x
-- code end

I tried to profile the code, but didn't find anything useful.
My bet is that all this "words . lines" is consuming more memory than
necessary, maybe saving space for the lines already processed.
Then I tried a some-what tail-call function, consuming one line at
each iteration:

-- code start
import Data.Char (toLower)

main :: IO ()
main = getLine >>= mainLoop

mainLoop :: [Char] -> IO ()
mainLoop s | (head s) == '*' = return ()
           | otherwise       = (putStrLn . toStr . isTautogram . words
$ s) >> main

toStr :: Bool -> [Char]
toStr True = "Y"
toStr False = "N"

isTautogram :: [[Char]] -> Bool
isTautogram (x:[]) = True
isTautogram (x:xs) = all ((== firstChar) . toLower . head) xs
    where firstChar = toLower . head $ x
-- code end

Note that the only thing that changed between the two tries was the main-loop.
The second version runs faster (got 0.11 secs) and with less memory (3.6 mb)

Can someone explain to me what is really going on?
Maybe pointing out how I can achieve these optimizations using
profiling information...

Thanks,
Thiago.

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to