Search code examples
haskellpattern-matchingnon-exhaustive-patterns

Pattern match(es) are non-exhaustive


I'm trying to create a function that eliminates multiples of a given Integer from a list of Integers, in the form multiples x [y], where x is the given Integer, and y is the list.

Here's what I have:

multiples :: Integer -> [Integer] -> [Integer]
multiples a [] = []
multiples a [b] = filter (\l -> l `mod` a /= 0) [b]

multiples will fail when called, saying "Non-exhaustive patterns in function multiples". So I used ghci -Wall with my file to see what patterns were missing, and it returns this:

multiples.hs:2:1: warning: [-Wincomplete-patterns]
    Pattern match(es) are non-exhaustive
    In an equation for `multiples': Patterns not matched: _ (_:_:_)

multiples.hs:2:11: warning: [-Wunused-matches]
    Defined but not used: `a'

I get the feeling I'm missing something really simple with line 2, but I'm a bit stuck. What am I doing wrong?


Solution

  • Welcome to Stack Overflow! There are a couple of things to fix in your function, but I'll start with the one you seem the most confused about: here [b] is a pattern matching a one-element list, naming its single item b. ([b, c] would be a pattern matching a two-element list, etc.) It's not a pattern matching an arbitrarily long list of bs. GHC is telling you off because you haven't accounted for the case where the function has been given a two-or-more-element list.

    If you want to match an arbitrary list of bs, omit the square brackets. Additionally, the first line of your function is not necessary because the second line already deals with that case.

    multiples :: Integer -> [Integer] -> [Integer]
    multiples a bs = filter (\b -> b `mod` a /= 0) bs
    

    Or, using a list comprehension,

    multiples :: Integer -> [Integer] -> [Integer]
    multiples a bs = [b | b <- bs, b `mod` a /= 0]
    

    Two more things: I'd name this function withoutMultiples because it filters out multiples of a, and because Haskell functions are curried by default you can omit the bs in the filter version.

    withoutMultiples :: Integer -> [Integer] -> [Integer]
    withoutMultiples a = filter (\b -> b `mod` a /= 0)