Jere
Jere

Reputation: 21

Haskell - Non-exhaustive pattern for a reason I don't understand

So I'm trying to write a function that, given two lists of integers, adds the ith even number of each list and returns them in another list. In case one of the list doesn't have an ith even number, a 0 is considered. For example, if the lists are [1,2,1,4,6] and [2,2], it returns [4,6,6] ([2+2,4+2,6+0]). I have the following code:

addEven :: [Int] -> [Int] -> [Int] 
addEeven [] [] = []
addEeven (x:xs) [] = filter (\g -> g `mod`2 == 0) (x:xs)
addEven [] (y:ys) = filter (\g -> g `mod` 2 == 0) (y:ys)
addEven (x:xs) (y:ys) = (a + b):(addEven as bs)
                        where 
                          (a:as) = filter (\g -> g `mod` 2 == 0) (x:xs)
                          (b:bs) = filter (\g -> g `mod` 2 == 0) (y:ys)

When I run that with the previous example, I get:

[4,6*** Exception: ex.hs:(4,1)-(8,101): Non-exhaustive patterns in function addEven

I really can't see what I'm missing, since it doesn't work with any input I throw at it.

Upvotes: 2

Views: 89

Answers (2)

Redu
Redu

Reputation: 26161

While using filter is very instinctive in this case, perhaps using filter twice and then summing up the results might be slightly ineffficient for large lists. Why don't we do the job all at once for a change..?

addMatches :: [Int] -> [Int] -> [Int]
addMatches [] [] = []
addMatches [] ys = filter even ys
addMatches xs [] = filter even xs
addMatches xs ys = first [] xs ys
                   where
                   first :: [Int] -> [Int] -> [Int] -> [Int]
                   first rs [] ys     = rs ++ filter even ys
                   first rs (x:xs) ys = rs ++ if even x then second [x] xs ys
                                                        else first [] xs ys
                   second :: [Int] -> [Int] -> [Int] -> [Int]
                   second [r] xs []     = [r] ++ filter even xs
                   second [r] xs (y:ys) = if even y then first [r+y] xs ys
                                                    else second [r] xs ys

λ> addMatches [1,2,1,4,6] [2,2]
[4,6,6]

Upvotes: 0

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476557

A filter might eliminate elements, hence filter (\g -> gmod2 == 0) is not said to return any elements, and thus the patterns (a:as) and (b:bs) might fail.

That being said, I think you make the problem too complex here. You can first define a helper function that adds two elements of a list:

addList :: Num a => [a] -> [a] -> [a]
addList (x:xs) (y:ys) = (x+y) : addList xs ys
addList xs [] = xs
addList [] ys = ys

Then we do the filter on the two parameters, and make a function addEven that looks like:

addEven :: Integral a => [a] -> [a] -> [a]
addEven xs ys = addList (filter even xs) (filter even ys)

or with on :: (b -> b -> c) -> (a -> b) -> a -> a -> c:

import Data.Function(on)

addEven :: Integral a => [a] -> [a] -> [a]
addEven = addList `on` filter even

Upvotes: 1

Related Questions