[Haskell-beginners] Re: Counting Fruits

Heinrich Apfelmus apfelmus at quantentunnel.de
Fri Feb 20 05:15:03 EST 2009


Adolfo Builes wrote:
> 
> I wanted to do a small program which read a txt with fruit's name in each
> line and then print how many fruits I have of each type. something like
> these:
>   apple
>   apple
> 
> and then
> 
> [(apple,2)]
> 
> I came up with this
> 
> import qualified Data.Map as Map
> import Data.List
> import System.IO
> 
> main =
>     do
>       file <- readFile "fruits.txt"
>       let answer = proccessFile $ lines file
> 
>       putStrLn (show answer)
> 
> proccessFile :: [String] -> [(String,Int)]
> proccessFile file = Map.toAscList $ parseFile Map.empty  file
>     where parseFile fruits [] = fruits
>           parseFile fruits_map (x:xs) = parseFile (Map.insertWith (+)
> x 1 fruits_map) xs
> 
> 
> It works, but I would like to know how would  you do it ?,  Share different
> points of view, different code. Was it a good idea to use a Map  ?, Did I
> separate the code  in a proper way, I mean pure - impure ? How can we
> improve the performance ?

Looks good to me. :)

Here's how I would write it

    main = print . process . lines =<< readFile "fruits.txt"

    process :: [String] -> [(String,Int)]
    process = Map.toAscList . foldl f Map.empty
        where f map x = Map.insertWith (+) x 1 map


So, the  parseFile  function is best expressed as a left fold and
function composition is good style.


The above works fine for smaller files. If you have larger amounts of
data, you will need a few strictness annotations or there will be a
space leak. In this case, this means using the functions

    foldl'  and  Map.insertWith'

instead of

    foldl   and  Map.insertWith

But I wouldn't bother about that for now.


Regards,
apfelmus

--
http://apfelmus.nfshost.com



More information about the Beginners mailing list