冗余模式匹配警告

时间:2019-10-15 22:30:09

标签: haskell pattern-matching

我正在编写一段返回函数的代码 像素列表,这是我定义的特殊数据类型,其类型如下:

data Pixel = Pixel {
                    color :: Float,
                    elevation :: Float,
                    distance: Float,
                    visited :: Bool
                   } deriving (Show)

我具有此功能,该功能将遍历两个文件并将它们放到一个像素列表中。这些文件分别包含颜色和高程,因此我继续获取此代码输出:

insertPixels :: [String] -> [String] -> [Pixel]
insertPixels _ _ = []
insertPixels (x:xs) (y:ys) = [Pixel (read x) (read y) 99999999 False] ++ insertPixels xs ys

当我尝试将其编译或加载到解释器中时,会出现此错误:

lab1.hs:33:1: warning: [-Woverlapping-patterns]
Pattern match is redundant
In an equation for ‘insertPixels’:
    insertPixels (x : xs) (y : ys) = ...
|
| insertPixels (x:xs) (y:ys) = [Pixel (read x) (read y) 99999999 False] ++ insertPixels xs ys
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我不太了解这是什么意思或我做错了什么。

2 个答案:

答案 0 :(得分:5)

只需切换两行的顺序,就像这样:

insertPixels :: [String] -> [String] -> [Pixel]
insertPixels (x:xs) (y:ys) = [Pixel (read x) (read y) 99999999 False] ++ insertPixels xs ys
insertPixels _ _ = []

问题在于insertPixels _ _匹配所有内容,并且由于模式是从上至下进行评估的,因此在第一个匹配项时停止,因此所有可能的输入都将导致空列表-显然不是您想要的。经更正后,递归大小写将在两个输入列表均为非空时生效,并且一旦其中一个为空,它将归结为“包罗万象”的情况并导致空列表。

请注意,使用(++)运算符将单个元素添加到列表的开头并不是特别习惯。您可以改用(:)(“ cons”)运算符:

insertPixels :: [String] -> [String] -> [Pixel]
insertPixels (x:xs) (y:ys) = (Pixel (read x) (read y) 99999999 False) : insertPixels xs ys
insertPixels _ _ = []

答案 1 :(得分:1)

下划线_是通配符,这意味着它与任何内容匹配:空列表,非空列表等。

因此,这意味着第一行将“触发”,无论您传递给insertPixels的值是什么。没有输入模式的第二行将“触发”,因此发出警告。

我们可以在空列表上使用模式匹配,例如:

insertPixels :: [String] -> [String] -> [Pixel]
insertPixels [] _ = []
insertPixels _ [] = []
insertPixels (x:xs) (y:ys) = [Pixel (read x) (read y) 99999999 False] ++ insertPixels xs ys

但是,您在这里描述的是一种众所周知的模式。 zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]。因此,我们可以将insertPixel定义为:

import Data.Function(on)

insertPixels :: [String] -> [String] -> [Pixel]
insertPixels = zipWith (\x y -> on Pixel read x y 99999999 False)

但是,我建议将readinsertPixels函数中删除,从而使用两个Float列表。如果您想使用read,则可以在呼叫者级别进行操作。