如何通过Pattern Synonyms抽象Text类型实现,满足指定模式匹配需求?
用模式同义词实现newtype的自定义模式匹配
要实现你想要的效果——让newtype Animal = Animal Text支持Human/NonHuman s的模式匹配,同时区分"human"和其他文本,且解耦实现与匹配语法,可以用GHC的**模式同义词(Pattern Synonyms)**扩展来完成。
模块内部实现(隐藏构造细节)
首先在定义Animal的模块里启用扩展,隐藏原始Animal构造函数,只导出自定义模式和安全的创建函数:
{-# LANGUAGE PatternSynonyms #-} module Animal ( Animal , pattern Human , pattern NonHuman , mkAnimal -- 安全构造函数,外部只能通过它创建Animal ) where import Data.Text (Text) newtype Animal = Animal Text -- 安全构造函数:确保不会生成非法的NonHuman "human" mkAnimal :: Text -> Animal mkAnimal "human" = Animal "human" mkAnimal s = Animal s -- 定义Human模式:匹配Animal "human" pattern Human :: Animal pattern Human = Animal "human" -- 定义NonHuman模式:仅匹配非"human"的Animal,且外部无法用它构造值 pattern NonHuman :: Text -> Animal pattern NonHuman s <- Animal s -- 去掉where子句,让NonHuman只能用于模式匹配,不能在表达式中创建实例
外部使用示例
在其他模块中导入Animal后,就能按你想要的方式模式匹配:
import Animal import Data.Text (Text) f :: Animal -> (Bool, Text) f = \case NonHuman s -> (False, s) Human -> (True, "human")
关键特性说明
- 模式匹配逻辑:
NonHuman s只会匹配包裹非"human"文本的Animal实例,Human精确匹配Animal "human",完全符合你的需求。 - 解耦实现与语法:外部不需要知道
Animal是基于Text的newtype,只需要使用Human和NonHuman模式即可。 - 限制非法构造:原始
Animal构造函数未导出,外部只能通过mkAnimal创建实例,避免出现NonHuman "human"这种非法值;同时NonHuman没有定义构造行为,外部无法在表达式中使用它创建值。
如果需要在模块内部允许用NonHuman构造合法值,可以给NonHuman加上where子句做合法性检查:
pattern NonHuman :: Text -> Animal pattern NonHuman s <- Animal s where NonHuman s = if s == "human" then error "NonHuman cannot be 'human'" else Animal s
内容的提问来源于stack exchange,提问作者Clinton
相关产品推荐
相关产品推荐

