我将 selectionSort 函数定义如下,对空列表进行排序只会产生一个空列表,并且排序非空列表是最小元素和列表其余部分的排序版本。
selectionSort :: Ord a => [a] -> [a]
selectionSort xs
| null xs = []
| otherwise = minElem : (selectionSort ys)
where
(minElem, ys) = minf xs
where
minf [x] = (x, [])
minf (x:xs) = let (m ,ms) = minf xs in
if x <= m then (x, xs)
else (m, x:ms)
minf 采用非空列表并返回最小值的元组和列表的其余部分。
当我使用-W标志编译此函数时,我收到此警告
warning: [-Wincomplete-patterns]
Pattern match(es) are non-exhaustive
In an equation for `minf': Patterns not matched: []
|
24 | minf [x] = (x, [])
| ^^^^^^^^^^^^^^^^^^...
函数minf
永远不会应用于空列表,因为这些案例会在null xs = []
中被捕获。有没有办法告知GHC,如果不使用其他类型(NonEmpty
列表类型)或Maybe
s
答案 0 :(得分:3)
通常的想法是“设计”类型,使“不可能的模式”的数量非常小(并且优选为零)。
作为穷人解决方案,您可以从以下位置重写该功能的签名:
foo :: [a] -> b -- [a] is a non-empty list
为:
foo :: a -> [a] -> b -- head and tail as input
因此,在这种情况下,我们可以将您的函数重写为:
selectionSort :: Ord a => [a] -> [a]
selectionSort [] = []
selectionSort (x:xs) = minElem : selectionSort ys
where (minElem, ys) = minf x xs
minf z [] = (z, [])
minf z za@(z2:zs) = let (m, ms) = minf z2 zs in
if z <= m then (z, za)
else (m, z:ms)
所以我们这里使用第一个参数作为列表的 head ,第二个参数作为尾部。由于列表至少包含一个元素,这意味着尾部可以为空,因此我们可以进行模式匹配。因此,我们仍然可以使用-Wincomplete-patterns
标志来检查是否涵盖了所有模式,因此我们仍然可以得到编译器的一些保证。
如果您仍无法正确设计类型,可以添加模式并引发(验证)错误:
minf [] = error "Impossible: minf only works with a non-empty list"