如何告知GHC特定模式匹配是不可能的(例如:列表永远不会为空)?

时间:2018-05-07 09:11:59

标签: haskell

我将 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

,则不可能发生特定情况

1 个答案:

答案 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"