如何为含多构造器与模式同义词的类型编写COMPLETE编译指示?
使用COMPLETE编译指示自动覆盖构造器与模式同义词
要解决手动枚举构造器易遗漏的问题,你可以利用GHC的COMPLETE编译指示结合通配符或类型引导,同时配合废弃标记区分被替换的构造器。
核心方案:通配符+废弃标记
假设你有一个包含大量构造器的类型,以及用于替换部分构造器的模式同义词:
-- 定义包含多构造器的类型 data BigType = A Int | B String | C Bool | D Double | E Char -- 后续可能新增F、G等构造器 -- 定义替换构造器的模式同义词 pattern MyA :: Int -> BigType pattern MyA x = A x pattern MyB :: String -> BigType pattern MyB s = B s
步骤1:用通配符自动包含所有构造器
使用..通配符指代BigType的所有构造器,再加上你的模式同义词,编写COMPLETE编译指示:
{-# COMPLETE MyA, MyB, .. #-}
这里的..会自动包含BigType的所有构造器(包括后续新增的),配合MyA和MyB组成完整的模式匹配集。
步骤2:标记被替换的构造器为废弃
为避免用户误用原构造器(比如A、B),用DEPRECATED编译指示标记它们:
{-# DEPRECATED A "请使用模式同义词MyA替代" #-} {-# DEPRECATED B "请使用模式同义词MyB替代" #-}
这样当有人直接使用A或B时,GHC会抛出警告,引导他们使用对应的模式同义词。
进阶方案:类型类引导(无命名规律场景)
如果构造器没有统一命名规律,且需要更精确控制完整集,可以用类型类标记需要包含的模式:
步骤1:定义标记用类型类
class CoversBigType p
这个类不需要任何方法,仅用于标记哪些模式属于完整匹配集。
步骤2:为模式同义词和保留的构造器创建实例
-- 为模式同义词的类型创建实例 instance CoversBigType (Int -> BigType) -- 对应MyA instance CoversBigType (String -> BigType) -- 对应MyB -- 为保留的构造器类型创建实例 instance CoversBigType Bool -- 对应C instance CoversBigType Double -- 对应D instance CoversBigType Char -- 对应E
后续新增构造器时,只需为其类型添加对应的CoversBigType实例即可,无需修改COMPLETE指示。
步骤3:指定COMPLETE编译指示
{-# COMPLETE CoversBigType #-}
GHC会自动将所有实现CoversBigType的模式和构造器视为完整匹配集。
注意事项
..通配符仅在GHC 8.10及以上版本支持;- 模式同义词默认是双向的(可用于模式匹配和表达式),若用
<-定义则为单向模式,仅能用于匹配; - 新增构造器时,通配符方案无需修改
COMPLETE;类型类方案只需添加对应实例。
内容的提问来源于stack exchange,提问作者dfeuer
相关产品推荐
相关产品推荐

