Search code examples
haskelldatabags

Map a list into a type


I am trying to transform a list ["a","b","c","c"] into a set in haskell, say: [("a",1),("b",1),("c",2)]. I am not trying to use maps. My function looks like so:

-- bagMyItem
bagMyItem :: Eq g => [g] -> Bag g -> Bag g
bagMyItem  (h:t) bag
     | h==q = (q,v+1):(listToBag t bag)  
     | null rBag = bag ++ [(h,1)]     
     | otherwise = (q,v):(listToBag (h:t) rBag)
     where ((q,v):rBag) = bag

Am I doing something wrong, or am I missing any case in this?


Solution

  • Here are my suggestions for how to solve this:

    Step 1: Initially I would write the functions with concrete types. When you make mistakes you'll get less cryptic error messages. Later you can go back and make the functions polymorphic.

    Step 2: Let's choose Char as our concrete type. Write a function which bags a single Char:

    type Bag g = [ (g,Int) ]
    
    bagSingleItem :: Char -> Bag Char -> Bag Char
    bagSingleItem c [] = ...
    bagSingleItem c ( (d,v) : bag ) = ...
    

    Step 3: Use this function to write one which bags a whole list of items:

    bagItems :: [Char] -> Bag Char -> Bag Char
    bagItems [] bag = ...
    bagItems (c:cs) bag =  ... bagSingleItem ...
    

    Step 4. Make your functions polymorphic. All you need to do is to change the type signatures of bagSingleItem and bagItems by replacing Char with a type variable and add the Eq ... constraint:

    bagSingleItem :: Eq g => g -> Bag g -> Bag g
    (definition remains the same)
    
    bagItems :: Eq g => [g] -> Bag g -> Bag g
    (definition remains the same)
    

    Or - even better - remove the type signatures completely and have ghci tell you what they are with the :t command:

    ghci> :t bagSingleItem
    ...
    ghci> :t bagItems
    ...