如何重构含字段的Haskell数据类型为标签化记录联合并解决模式覆盖错误?
问题解答
错误原因
GHC的穷尽性检查默认只识别数据类型的原始构造器(这里是A和BTag),而你定义的B是模式同义词——本质是语法层面的匹配糖,GHC不会自动将其与BTag的覆盖关系关联起来。因此检查器认为foo只匹配了A,漏掉了BTag分支,抛出非穷尽匹配错误。
模式同义词的使用问题
你定义的B是双向模式(可用于匹配和构造),但默认情况下它不会被纳入穷尽性检查的覆盖集合。要让GHC认可它作为D类型的“构造分支”,需要显式声明。
实现预期重构的方法
启用CompletePatterns扩展,并用COMPLETE注解告诉GHC:A和B这两个模式共同覆盖了D类型的所有可能情况。修改后的代码如下:
{-# LANGUAGE PatternSynonyms, CompletePatterns #-} {-# OPTIONS_GHC -Werror=incomplete-patterns #-} data D = A | BTag BRec data BRec = BRec { _bInt :: Int, _bString :: String } pattern B :: Int -> String -> D pattern B{ bInt, bString } = BTag (BRec bInt bString) -- 声明A和B是D类型的完整模式集合 {-# COMPLETE A, B #-} foo :: D -> String foo A{} = "A" foo B{bString = x} = x
关键说明
COMPLETE注解直接指定了匹配D类型时需要覆盖的模式集合,GHC会据此进行穷尽性检查,不再考虑原始构造器BTag。- 这种修改完全保留了原有模式匹配的写法,符合你“无需修改数据类型的任何模式匹配”的核心要求。
- 该方案要求GHC版本在8.0及以上(
CompletePatterns扩展从GHC 8.0开始支持)。
内容的提问来源于stack exchange,提问作者Andreas Abel
相关产品推荐
相关产品推荐

