Though disjoint
exhausts all possible patterns in its guard conditions, Haskell gives me a PatternMatchFail
error when running it.
disjoint :: (Ord a) => [a] -> [a] -> Bool
disjoint l@(x:xs) r@(y:ys)
| null l || null r = True
| x == y = False
| x > y = disjoint l ys -- reduce right list
| otherwise = disjoint xs r -- reduce left list
-- | Terminates when either list has been reduced to null, or when their head
-- elements are equal. Since lists are ordered, it only needs to compare head elements.
However, it has no problem if I write:
disjoint :: (Ord a) => [a] -> [a] -> Bool
disjoint [] _ = True
disjoint _ [] = True
disjoint l@(x:xs) r@(y:ys)
-- | null l || null r = True -- now redundant, but included for sake of continuity
| x == y = False
| x > y = disjoint l ys -- reduce right list
| otherwise = disjoint xs r -- reduce left list
Without those additional lines, I get a PatternMatchFail
. If I am to infer what the issue for Haskell is in the first case, it is that if given a null list for an input argument, its expected arguments l@(x:xs) r@(y:ys)
are already invoking a pattern-match, one that is non-exhaustive in the case of a null list, resulting in a PatternMatchFail
, despite having a guard condition that checks for exactly the same condition. It just can't ever reach the guard condition, because it first needs to match on the "argument condition".
However, those additional two lines are a tad off-putting to me in their repetitiveness, and I was just wondering if there was a more succinct way of fixing this. More generally: if I were to be using three or more lists as arguments, I definitely wouldn't want to write out disjoint 3+ more times just to check for null conditions, so what might I do in cases like that? Thank you for your time.