Home > database >  Function to increase count of a tuple in Haskell
Function to increase count of a tuple in Haskell

Time:10-08

So I have a function that takes a character and a list of tuples [tuple is a pair containing a character and an integer]. If the character matches the tuple character, the corresponding number is incremented by one. If not, then the tuple is printed as is.

So basically

foo 'a' [('a',1),('b',2),('c',1)]

Should yield

[('a',2),('b',2),('c',1)]

I have written the following code, but understandably, it skips printing over the last tuple:

foo a ((x,y):xs) | xs == [] = []
                 | x==a = (x,y 1):foo a xs
                 | x/=a = (x,y):foo a xs

foo 'a' [('a',1),('b',2),('c',1)]
O/P : [('a',2),('b',2)]

How do I modify the function such that it considers the last tuple too? I'd also like to be able to add a tuple with a count of 1 if the element is not present in the list of tuples

CodePudding user response:

Note what happens if we try to apply foo to the empty list:

λ> foo 'a' []
*** Exception: <interactive>:(90,1)-(92,40): Non-exhaustive patterns in function foo

It is generally frowned upon to use guards for things you can pattern match. Let's rewrite foo a bit, hopefully, it will make the cause of the exception clear and help you see what should be do to fix the problem:

foo _ (_:[]) = [] -- the pattern could also be `[_]`
foo a ((x,y):xs) | x==a = (x,y 1):foo a xs
                 | x/=a = (x,y):foo a xs

Now it's evident one element lists are discarded:

λ> foo 'a' [('a',1)]
[]

Let's this. Also, the guard forces us to replicate work, let's remove it.

foo _ [] = []
foo a ((x,y):xs) = (x, if x == a then y 1 else y):foo a xs

And voilà:

λ> foo 'a' []
[]
λ> foo 'a' [('a',1)]
[('a',2)]
λ> foo 'b' [('a',1),('b',2),('c',3)]
[('a',1),('b',3),('c',3)]

CodePudding user response:

Your xs == [] case needs to be done at the same level as the pattern match, not after it.

foo :: a -> [(a, Int)] -> [(a, Int)]
foo _ [] = []
foo a ((x, y):xs)
  | x==a      = (x, y   1) : foo a xs
  | otherwise = (x, y    ) : foo a xs

Your version only checks that the tail (excluding the first element) is empty. You want to check if the whole list is empty and handle that case differently.

Side note: If you compile Haskell with -Wall, it will warn you about the partial function. I recommend always using -Wall. 99% of the things it warns you about are genuinely good advice, and the handful of silly warnings can be easily disabled on-demand.

  • Related