3

在您将其视为重复项之前

我看到至少截至 2018 年 9 月,GHCI 不允许您在本地禁用警告(尽管您可以在整个文件中)。

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

问题

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

例子

(有关激发这个玩具示例的真实代码,请参见pExprToHExpr 此处的定义。)

这段代码:

{-# 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可能具有最高音调,如果它包含 a Cowbell,那么它不适合 thePercussivePitched类型。

4

2 回答 2

4

我会颠倒哪个功能是“确定的”。即使乐器已调好,您仍然必须指定一些最高音调,同时highestPitch提供您需要知道的所有东西,以了解乐器是否已调好。因此

-- An instrument with a highest pitch is pitched; the others aren't.
pitched :: Instrument -> Bool
pitched = either (const False) (const True) . highestPitch


highestPitch :: Instrument -> Either String Float
highestPitch (Drums (Just Cowbell)) = Right 800
highestPitch Violin                 = Right 5000
highestPitch Oboe                   = Right 2000
highestPitch Rattle = Left "Instrument Rattle has no pitch"
highestPitch (Drums Nothing) = Left "Instrument Drums Nothing has no pitch"
于 2019-02-16T19:18:05.537 回答
3

考虑到pitched. 因此,检查器基本上忽略了第一个等式,从而引发了警告。

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

为了使警告静音,我可以看到两个主要选项。第一个是在最后添加一个catch all case。

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包含错误,这将默默地产生本不存在的音调。

实际上,正如评论中所指出的,还有第三种方法:使用PatternSynonymsCOMPLETEpragma 来说服 GHC 使警告静音。然而,这是更高级的。虽然它在设计库中肯定有其用途,但对于这种特定情况,它可能有点矫枉过正。

于 2019-02-16T19:02:19.070 回答