Haskell中混合类型模式匹配与记录语法的编译问题
GADT匹配:类型应用与记录语法结合的解决方案
问题场景
我们定义了带记录字段的GADT及相关函数:
data T where T :: (Typeable a, Integral a) => { first :: a, second :: a } -> T printType :: forall a. Typeable a => String printType = show $ typeRep (Proxy :: Proxy a) f :: T -> String f (T first second) = show (toInteger first, toInteger second)
单独使用记录语法匹配字段是可行的:
f (T {first, second}) = show (toInteger first, toInteger second)
单独使用类型应用获取GADT的类型参数也没问题:
f (T @a first second) = printType @a ++ ": " ++ show (toInteger first, toInteger second)
但尝试将两者结合时,f (T @a {first, second})会编译失败——GHC目前不支持这种语法组合。
可行的替代方案
1. As模式+记录访问器
直接用As模式绑定整个值,匹配类型参数后通过记录访问器提取字段,无需额外语法扩展:
f t@(T @a _ _) = printType @a ++ ": " ++ show (toInteger (first t), toInteger (second t))
2. As模式+局部记录模式匹配
如果觉得访问器写法不够直观,可以用局部绑定提取记录字段,开启扩展后还能进一步简化:
f t@(T @a _ _) = let T{first, second} = t in printType @a ++ ": " ++ show (toInteger first, toInteger second)
开启RecordWildCards扩展后,写法更简洁:
{-# LANGUAGE RecordWildCards #-} f t@(T @a _ _) = let T{..} = t in printType @a ++ ": " ++ show (toInteger first, toInteger second)
3. 视图模式(需开启ViewPatterns)
借助视图模式可以把类型匹配和字段提取整合到模式中,不过需要额外开启扩展:
{-# LANGUAGE ViewPatterns #-} f (T @a -> T {first, second}) = printType @a ++ ": " ++ show (toInteger first, toInteger second)
总结
截至GHC 9.6版本,官方语法仍不支持直接将类型应用与记录模式结合,但上述几种方案都能简洁实现需求,其中As模式+记录访问器是最轻量化的选择,无需任何额外扩展。
内容的提问来源于stack exchange,提问作者Clinton
相关产品推荐
相关产品推荐

