Haskell模式同义词中提取公共常量的相关技术疑问
Haskell模式同义词相关问题解答
问题背景
我原本有这段代码:
newtype T = T Text pattern Alice = T "Alice"
这没问题,但因为其他地方也要用到"Alice",我把它提取成了顶层值:
alice :: Text alice = "Alice" pattern Alice = T alice
开启警告编译时收到了未使用变量的警告,这时候我才意识到,pattern Alice = T alice其实会匹配所有T类型的值,而非仅匹配T "Alice"。另外我还觉得T "Alice"能作为模式被允许有点奇怪,毕竟"Alice"是计算得到的Text值。后来在Overloaded Strings的文档里看到:
字符串字面量的行为非常类似整数字面量,即可同时用于表达式和模式中。若用于模式中,字面量会被替换为相等性测试,就像整数字面量一样。
由此引出两个问题:
- 不启用Overloaded Strings扩展,我能否编写Alice模式?
- 能否创建右侧需要计算的模式同义词,让GHC像处理数值和字符串字面量一样使用Eq进行匹配?还是数值和字符串字面量是特殊情况,GHC不允许泛化该功能?
问题解答
1. 不启用Overloaded Strings能否编写Alice模式?
可以,但需要结合其他扩展调整写法:
- 不启用Overloaded Strings时,字符串字面量
"Alice"的类型是String,而T构造器接受的是Text,直接写T "Alice"会出现类型不匹配。 - 使用ViewPatterns扩展可实现单向匹配模式:
{-# LANGUAGE ViewPatterns #-} import Data.Text (Text, pack) newtype T = T Text pattern Alice <- T (pack "Alice" -> ())
- 如果需要既能匹配又能构造的双向模式,可结合PatternSynonyms扩展:
{-# LANGUAGE PatternSynonyms #-} import Data.Text (Text, pack) newtype T = T Text pattern Alice :: T pattern Alice = T (pack "Alice")
这里的pack "Alice"会在构造时被求值,匹配时则依赖GHC对这种“字面量转换表达式”的特殊处理,本质上是把它当作常量模式来匹配。
2. 能否创建依赖计算值的模式同义词,让GHC用Eq匹配?
数值和字符串字面量确实是GHC的特殊处理情况,编译器会自动将它们的模式匹配转换为相等性测试,但目前没有直接语法支持将任意计算值泛化为这种模式。不过可以通过以下方式实现类似效果:
- 使用ViewPatterns实现匹配逻辑:通过视图模式提取值并显式做相等性检查:
{-# LANGUAGE ViewPatterns #-} import Data.Text (Text) alice :: Text alice = "Alice" newtype T = T Text pattern Alice <- T (\x -> x == alice -> True)
这个模式会提取T包裹的Text,检查它是否等于预定义的alice,符合条件则匹配成功。
- 定义双向模式同义词:如果需要模式既能匹配又能构造,可结合
PatternSynonyms和ViewPatterns:
{-# LANGUAGE PatternSynonyms, ViewPatterns #-} import Data.Text (Text) alice :: Text alice = "Alice" newtype T = T Text pattern Alice :: T pattern Alice <- T (== alice -> True) where Alice = T alice
where子句定义了模式的构造逻辑,匹配时则通过视图模式做相等性检查。
简单来说:数值、字符串字面量是编译器特殊优化的情况,但你可以通过ViewPatterns或带显式逻辑的模式同义词,实现基于Eq实例的自定义匹配模式。
内容的提问来源于stack exchange,提问作者Clinton
相关产品推荐
相关产品推荐

