Haskell如何将ADT构造器作为类型以简化VRecord相关函数定义
最优解决方案:提取独立的Record类型
这是Haskell场景下处理这类需求的标准实践,改动量极小且兼容性最高:
- 首先重构类型定义,将
VRecord的载荷抽为独立类型(推荐用newtype封装获得更强的类型安全,也可以用type别名零成本兼容原有代码)
type Keyword = Text -- 用newtype封装避免和普通[DBField]混用,无额外运行时开销 newtype Record = Record [DBField] deriving (Eq, Show, Read) data DBField = (:=) Keyword DBVal deriving (Show, Read, Eq) data DBVal = VNull | VInt Int64 | VDouble Double | VBool Bool | VString Text | VUTCTime UTCTime | VArray [DBVal] | VObjId ObjectId | VUUID UUID | VRecord Record -- 改为使用抽离的Record类型 deriving (Eq, Show, Read)
- 直接实现你需要的签名的
get函数,完全不需要处理其他DBVal分支:
get :: Record -> Keyword -> Maybe DBVal get (Record fields) target = foldr match Nothing fields where match (kw := val) acc = if kw == target then Just val else acc
- 可选补充一个投影辅助函数,方便从
DBVal实例中提取Record,避免重复写模式匹配:
asRecord :: DBVal -> Maybe Record asRecord (VRecord r) = Just r asRecord _ = Nothing
需要从DBVal中查询字段时可以直接组合使用:
-- 示例:从DBVal类型的val中查询名为"username"的字段 asRecord val >>= flip get "username"
不可修改原有DBVal定义时的备选方案
如果受项目约束不能修改原有类型定义,可以开启GHC的PatternSynonyms扩展定义虚拟的Record类型匹配,不过兼容性弱于抽离独立类型的方案,不优先推荐。
内容的提问来源于stack exchange,提问作者Farzad Bekran
相关产品推荐
相关产品推荐

