在将其视为重复之前
之前我看到,至少从2018年9月开始,GHCI不允许您在本地禁用警告(尽管您可以在整个文件中)。
,但也许还有其他方法可以让GHCI知道每种情况实际上都在处理?
问题
我有时会使用一个习语是写一个函数,其中第一个定义(S)测试了一些谓词和返回,而其他定义则考虑操作实际上有意义的参数。每当我这样做时,我都会得到"模式匹配(ES)是非详尽的"错误,但是我确实在检查每个条件。
示例
(对于激励这个玩具示例的现实世界代码,请参见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
可能具有最高的音高,如果它包括Cowbell
,因此它不适合Percussive
或Pitched
类型。
i会逆转哪个函数为"确定性"。即使音调仪器,您仍然必须分配一些最高的音高,而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"
GHC未考虑pitched
的定义。因此,Checker基本上忽略了第一个方程式,从而引起了警告。
的确,从计算科学的角度来看,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
包含一个错误,这将默默产生应该不存在的音调。
实际上,正如上面在评论中指出的那样,有第三种方法:使用PatternSynonyms
和COMPLETE
Pragma说服GHC使警告保持沉默。但是,这更为先进。虽然它绝对具有设计库的用途,但对于这种特定情况,它可能有点过分。