Nic*_*año 3 haskell pattern-matching non-exhaustive-patterns
虽然disjoint在保护条件下耗尽了所有可能的模式,但Haskell PatternMatchFail在运行时会给我一个错误.
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.
Run Code Online (Sandbox Code Playgroud)
但是,如果我写,它没有问题:
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
Run Code Online (Sandbox Code Playgroud)
没有那些额外的线,我得到了PatternMatchFail.如果我要在第一种情况下推断出Haskell的问题是什么,那么如果为输入参数提供了一个空列表,那么它的预期参数l@(x:xs) r@(y:ys)已经在调用一个模式匹配,在这种情况下它是非详尽的.一个空列表,导致a PatternMatchFail,尽管有一个保护条件,检查完全相同的条件.它只是无法达到保护条件,因为它首先需要匹配"参数条件".
然而,那些额外的两行在重复性方面对我来说有点令人反感,我只是想知道是否有更简洁的方法来解决这个问题.更一般地说:如果我使用三个或更多列表作为参数,我绝对不想写出不相交3次以上只是为了检查空条件,那么在这样的情况下我可以做些什么呢?感谢您的时间.
ben*_*ofs 12
你解释为什么这会导致模式匹配失败是正确的.您可以通过以下方式编写代码以避免冗余行:
disjoint :: (Ord a) => [a] -> [a] -> Bool
disjoint l@(x:xs) r@(y:ys)
| x == y = False
| x > y = disjoint l ys -- reduce right list
| otherwise = disjoint xs r -- reduce left list
disjoint _ _ = True -- catch all pattern, executed if either l or r is []
Run Code Online (Sandbox Code Playgroud)
这是我推荐的解决方案.还有另一种解决方案,使模式匹配更加懒惰(只有在x/ xs或y/ ys实际需要时才检查模式):
disjoint :: (Ord a) => [a] -> [a] -> Bool
disjoint l@ ~(x:xs) r@ ~(y:ys) -- the ~ here says that this is an irrefutable pattern, which makes the match more lazy
| null l || null r = True -- x/y is not required, so pattern not checked
| x == y = False
| x > y = disjoint l ys -- reduce right list
| otherwise = disjoint xs r -- reduce left list
Run Code Online (Sandbox Code Playgroud)
我不建议这样做,因为null明确地检查并不像惯用的Haskell(同样,很少使用无可辩驳的模式).第二种方法的问题是你必须注意你不能访问y/ys/ x/xs在null情况下,编译器将无法帮助你.第一种方法保证在null情况下无法访问它们.