避免在GHCI中使用不适当的非穷尽模式匹配警告

时间:2019-02-16 18:01:31

标签: haskell pattern-matching warnings suppress-warnings non-exhaustive-patterns

在将其作为重复项消除之前

我至少看到了GHCI does not allow you to disable a warning locally,直到2018年9月(尽管您可以查看整个文件)。

但是也许还有其他方法可以让GHCI知道实际上每个案件都在处理中?

问题

我有时使用的一个惯用法是编写一个函数,其中第一个定义测试某些谓词并返回Left,而其他定义则考虑该操作实际上有意义的参数。每当我这样做时,都会收到“模式匹配不详尽”错误,但实际上我正在检查每种情况。

示例

(有关激发该玩具示例的真实代码,请参见例如pExprToHExpr here的定义。)

此代码:

{-# LANGUAGE ViewPatterns #-}

data Cowbell = Cowbell
  deriving Show
data Instrument = Rattle
                | Drums (Maybe Cowbell)
                | Violin
                | Oboe
  deriving Show

pitched :: Instrument -> Bool
pitched Rattle                 = False
pitched (Drums Nothing)        = False
pitched (Drums (Just Cowbell)) = True
pitched Violin                 = True
pitched Oboe                   = True

highestPitch :: Instrument -> Either String Float
highestPitch i@(pitched -> False) =
  Left $ "Instrument " ++ show i ++ " has no pitch."
highestPitch (Drums (Just Cowbell)) = Right 800
highestPitch Violin                 = Right 5000
highestPitch Oboe                   = Right 2000

产生此错误:

example.hs:19:1: warning: [-Wincomplete-patterns]
    Pattern match(es) are non-exhaustive
    In an equation for ‘highestPitch’:
        Patterns not matched:
            Rattle
            (Drums Nothing)

在其他情况下,我将细分Instrument类型:

data Percussive = Rattle | Drums
data Pitched    = Violin | Oboe
data Instrument = Percussive Percussive
                | Pitched Pitched

但是(在这种虚构的物理学中)一组Drums可能具有最高音调,如果它包含Cowbell,那么它既不适合Percussive也不适合Pitched类型。

2 个答案:

答案 0 :(得分:4)

我会反转哪个功能是“确定的”。即使乐器已调高音调,您仍必须指定一些最高音调,而clean install提供了您需要知道乐器是否调高音调的所有信息。因此

highestPitch

答案 1 :(得分:2)

GHC不会考虑pitched的定义来检查详尽性。因此,检查人员实际上忽略了第一个方程,从而引发警告。

实际上,从计算科学的角度来看,GHC无法在一般情况下做出决定,因为存在视图模式时的穷举性尚不确定。充其量来说,GHC可能会使用一些复杂的静态分析,但它只是选择完全忽略pitched

要使警告静音,我可以看到两个主要选项。第一种是在末尾添加全部内容。

highestPitch :: Instrument -> Either String Float
highestPitch i@(pitched -> False) =
  Left $ "Instrument " ++ show i ++ " has no pitch."
highestPitch (Drums (Just Cowbell)) = Right 800
highestPitch Violin                 = Right 5000
highestPitch Oboe                   = Right 2000
highestPitch i                      =
  Left $ "Instrument " ++ show i ++ " has no pitch."
  -- we could even use "error", in certain cases

如果遵循这条路线,在这种情况下,我们可以删除第一个方程式。

highestPitch :: Instrument -> Either String Float
highestPitch (Drums (Just Cowbell)) = Right 800
highestPitch Violin                 = Right 5000
highestPitch Oboe                   = Right 2000
highestPitch i                      =
  Left $ "Instrument " ++ show i ++ " has no pitch."

或者,我们可以使最后一种情况Oboe笼统:

highestPitch :: Instrument -> Either String Float
highestPitch i@(pitched -> False) =
  Left $ "Instrument " ++ show i ++ " has no pitch."
highestPitch (Drums (Just Cowbell)) = Right 800
highestPitch Violin                 = Right 5000
highestPitch _oboe                  = Right 2000   -- must be an Oboe

不过,我不是这种方法的忠实拥护者,因为如果pitched包含错误,它将以静默方式产生本不应该存在的音调。

实际上,如上面评论中所指出的,还有第三种方法:使用PatternSynonymsCOMPLETE编译指示说服GHC取消警告。但是,这更高级。尽管在设计库时肯定有它的用途,但对于这种特定情况,可能有点过大。