"Pattern match is redundant" when using input list argument inside list comprehension

Viewed 123

This is my code:

example = [1,-4,7,12]

positiveSum :: [Int] -> Int
positiveSum (x) = 0
positiveSum (x:xs) = result
  where 
    result = sum [y+y | y <- xs, y > 0]

main = do
  print (positiveSum example)

When I run it I get:

Main.hs:5:1: warning: [-Woverlapping-patterns]
    Pattern match is redundant
    In an equation for `positiveSum': positiveSum (x : xs) = ...
  |
5 | positiveSum (x:xs) = result
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^...

I can't use 'xs' inside the list comprehension and I don't understand why. It's a reference, and I should be able to use it. Why is it redundant?

Edit:

The answer solved the problem, I was matching anything with the first (x). Also, I confused myself and was applying sum twice. This is the right code:

positiveSum :: [Int] -> Int
positiveSum [] = 0
positiveSum xs = result
  where 
    result = sum [x | x <- xs, x > 0]
3 Answers

You seem to think positiveSum (x) = 0 will only match the case of an empty list, but that will in fact match anything, which makes the next line redundant since it will never get tried. You meant to write positiveSum [] = 0 there. Also, note that your second case, even though it will now run, will throw away the head of the list, which you probably didn't mean to do.

Pattern matches go top to bottom, so every call to positiveSum returns 0. Since the pattern for the first rule is positiveSum (x) = 0, which matches everything, since every value can be bound to x. By making that rule the last one, you can avoid this issue:

positiveSum :: [Int] -> Int
positiveSum (x:xs) = result
  where 
    result = sum [y+y | y <- xs, y > 0]
positiveSum (x) = 0

With this code, we only fall back to the 0 case if there isn't a tail for the argument, causing the expected behaviour.

You do not need to make a distinction between an empty list and a non-empty list: you can calculate the sum of the filtered list with:

positiveSum :: [Int] -> Int
positiveSum xs = sum [y | y <- xs, y > 0]

Here xs pattern matches thus with all possible lists: empty or not empty. y will enumerate over all items of xs, and if y > 0, we yield that value. We then calculate the sum of that list. For an empty list sum will return 0, so regardless if xs is empty or not, and that there are elements that satisfy the y > 0 predicate, it will return a value.

Another option is to work with filter :: (a -> Bool) -> [a] -> [a] and thus determine the sum with:

positiveSum :: [Int] -> Int
positiveSum = sum . filter (0 <)
Related