haskell - 如何通知 GHC 特定模式匹配是不可能的(例如:列表永远不会为空)?
问题描述
我定义了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 ,特定情况是不可能的
解决方案
通常的想法是“设计”类型,使“不可能的模式”的数量非常少(最好为零)。
作为穷人解决方案,您可以从以下位置重写函数的签名:
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)
所以我们这里使用第一个参数作为列表的头部,第二个作为尾部。由于列表至少包含一个元素,这意味着尾部可以为空,因此我们可以进行模式匹配。结果,我们仍然可以使用该-Wincomplete-patterns
标志来检查是否所有模式都被覆盖,因此我们仍然可以得到编译器的一些保证。
如果您仍然无法正确设计类型,您可以添加模式并引发(验证)错误:
minf [] = error "Impossible: minf only works with a non-empty list"
推荐阅读
- javascript - 套接字 io 未接收客户端和服务器的事件
- jquery - 动态 CSS 值
- codenameone - Form.getCommand(int index) 是如何工作的?
- java - 如何在 Java 中为 iCalendar 设置时区?
- tree - 试图在 Racket n-ary 中写 Foldtree 只知道如何写二叉树
- reactjs - FlattList 不滚动所有内容
- python - 有没有一种简单的方法可以递归地将 __name__ 添加到 MagicMock 属性中
- kubernetes - Kubernetes 处理处理能力的突然请求(例如使用 5 个进程的 Python 脚本)
- node.js - 如何设置我的后端服务器而不在每次重新启动时重写数据
- scala - Building Scala project with docker's Multi-Stage