Haskell Pattern Synonyms等特性使用两类报错原因与解决方法咨询
模式同义词报错原因、解决方法与工作原理说明
第一个报错:non-bidirectional pattern synonym used in an expression
触发原因
你定义的IsTrue是单向模式同义词,仅声明了匹配规则(用<-表示),没有定义对应的构造逻辑,因此只能出现在模式匹配的位置,不能作为值/构造函数放在表达式中调用。你写的test10 = IsTrue "True"属于将单向模式同义词当作表达式使用,不符合语法规则。
解决方法
两种可选方案:
- 仅测试匹配功能:将
test10改为模式匹配写法
{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE GADTs #-} pattern IsTrue :: Show a => a pattern IsTrue <- ((== "True") . show -> True) test10 = case "True" of IsTrue -> "匹配成功" _ -> "匹配失败"
- 改为双向模式同义词:补充构造逻辑,允许作为表达式使用
{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE GADTs #-} pattern IsTrue :: Show a => a pattern IsTrue <- ((== "True") . show -> True) where IsTrue = read "True" -- 补充构造逻辑,返回show结果为"True"的值 test10 = IsTrue :: Bool -- 此时可作为表达式调用,取值为True
第二个报错:No instance for (Show T) arising from a use of ‘print’
触发原因
该报错和模式同义词本身无关:你定义的GADT类型T没有实现Show实例,在GHCi中直接运行test11时,GHC会默认调用print输出结果,而print要求参数实现Show类型类,因此触发报错。test11本身的编译逻辑是合法的。
解决方法
给T类型实现Show实例即可,可直接复用内部存储字段的Show能力:
{-# LANGUAGE GADTs #-} {-# LANGUAGE PatternSynonyms #-} data T where MkT :: (Show b) => b -> T -- 手动实现Show实例 instance Show T where show (MkT x) = "MkT " ++ show x pattern ExNumPat :: () => Show b => b -> T pattern ExNumPat x = MkT x test11 = ExNumPat True -- 运行会输出 "MkT True"
两类模式同义词的工作原理
1. 单向模式同义词
语法为pattern 模式名 <- 匹配逻辑,仅可用于模式匹配场景:
- 匹配时会执行声明的匹配逻辑对目标值做校验/转换,符合条件则匹配成功。你定义的
IsTrue结合了ViewPatterns扩展,匹配时会先对目标执行show,再判断结果是否等于"True",满足则匹配通过。 - 没有声明构造逻辑,因此无法作为表达式/构造函数使用。
2. 双向模式同义词
包含两种写法:一种是pattern 模式名 参数 = 构造逻辑,另一种是单向模式后加where块补充构造逻辑,既可以用于模式匹配,也可以作为构造函数在表达式中使用:
- 作为表达式使用时,等价于直接调用你声明的构造逻辑生成对应值,你定义的
ExNumPat x = MkT x作为表达式调用时,等价于直接调用MkT构造T类型的值。 - 作为模式匹配使用时,会匹配构造逻辑对应的取值,将内部字段绑定到参数上。
- 模式同义词的双约束类型签名中,前一层
()包裹的约束是匹配成功后对外提供的上下文,后一层约束是构造/使用该模式时需要满足的约束。
内容的提问来源于stack exchange,提问作者maxloo
相关产品推荐
相关产品推荐

