You can use -Werror
to turn warnings into errors. I don't know if you can turn just the non-exhaustive patterns warnings into errors, sorry!
As for the third part of your question:
I sometimes write a number of functions which tend to work closely together and have properties which you can't easily express in Haskell. At least some of these functions tend to have non-exhaustive patterns, usually the 'consumers'. This comes up, for example in functions which are 'sort-of' inverses of each other.
A toy example:
duplicate :: [a] -> [a]
duplicate [] = []
duplicate (x:xs) = x : x : (duplicate xs)
removeDuplicates :: Eq a => [a] -> [a]
removeDuplicates [] = []
removeDuplicates (x:y:xs) | x == y = x : removeDuplicates xs
Now it's pretty easy to see that removeDuplicates (duplicate as)
is equal to as
(whenever the element type is in Eq
), but in general duplicate (removeDuplicates bs)
will crash, because there are an odd number of elements or 2 consecutive elements differ. If it doesn't crash, it's because bs
was produced by (or could have been produced by) duplicate
in the first place!.
So we have the following laws (not valid Haskell):
removeDuplicates . duplicate == id
duplicate . removeDuplicates == id (for values in the range of duplicate)
Now, if you want to prevent non-exhaustive patterns here, you could make removeDuplicates
return Maybe [a]
, or add error messages for the missing cases. You could even do something along the lines of
newtype DuplicatedList a = DuplicatedList [a]
duplicate :: [a] -> DuplicatedList a
removeDuplicates :: Eq a => DuplicatedList a -> [a]
-- implementations omitted
All this is necessary, because you can't easily express 'being a list of even length, with consecutive pairs of elements being equal' in the Haskell type system (unless you're Oleg :)
But if you don't export removeDuplicates
I think it's perfectly okay to use non-exhaustive patterns here. As soon as you do export it, you'll lose control over the inputs and will have to deal with the missing cases!