import IO import Char data BTree a = Node a Int (Maybe (BTree a)) (Maybe (BTree a)) type Dictionary = (Maybe (BTree String)) update newWord dict = case dict of Nothing -> Just (Node newWord 1 Nothing Nothing) Just node -> update' newWord node update' newWord (Node word count left right) | word == newWord = Just (Node word (count + 1) left right) | word < newWord = Just (Node word count left (update newWord right)) | word > newWord = Just (Node word count (update newWord left) right) toList = toList' [] toList' list node = case node of Nothing -> list Just (Node word count left right) -> toList' ((word, count) : toList' list right) left isLetter c = isAlphaNum c || c=='\'' normalize = map toLower . filter isLetter isWord [] = False isWord s = True nwords = filter isWord . map normalize . words wordCount = length . words wordTotals = toList . foldr update Nothing . nwords wordFrequency s = let total = (fromIntegral . wordCount) s freq = \(word, count) -> (word, (fromIntegral count) / total) in (map freq . wordTotals) s format (word, frequency) = show word ++ ": " ++ show frequency main = do input <- hGetContents stdin (mapM (hPutStrLn stdout) . map format . wordFrequency) input