PAYATHON 2026

Haskell 的 pattern synonym 能否只提供 Foo 构造语法?

数据小陈

结论

pattern synonym 必须定义匹配行为。单向 pattern synonym 只能用于匹配,双向 pattern synonym 则同时支持匹配和构造。若要用 Foo abcd 构造一个 Bar,还需要定义 Foo 如何匹配。

Bar 保存的是一个函数,而问题中没有说明如何从这个函数还原 (String, String, String, String)。如果无法还原这些值,就无法为 Foo 定义有意义的匹配行为,也就不能把 Foo 直接用作只负责构造 Bar 的大写语法糖。

为什么无法只保留构造方向

问题中的旧类型是:

data Foo = Foo (String, String, String, String)

新类型则是:

data Bar = Bar (Bool -> Int -> Bool -> String)

构造时可以把四元组中的值捕获到函数闭包中,再用这个函数构造 Bar。匹配时则需要给定一个 Bar,并从中取出 Foo 所需的四元组。一般而言,函数值不包含可供程序可靠取回的原始输入,因此这两个方向无法自然互逆。

Pattern synonym 的构造逻辑可以不同于匹配表达式,但仍需定义匹配模式。不能只声明一个构造器式的 Foo,却不提供相应的匹配定义。

可选方案

如果调用处可以改用小写函数名,直接提供构造函数会更简单:

mkFoo :: (String, String, String, String) -> Bar
mkFoo (a, b, c, d) =
  Bar (\b1 i b2 -> libraryFunction a b c d b1 i b2)

libraryFunction 只是示意名称,应替换为库中实际生成结果的逻辑。调用方使用 mkFoo abcd。

如果需要保留 Foo abcd 这种构造语法,可以将 Bar 的表示设计成能够还原四元组,或者继续保留 Foo 作为独立类型,并明确提供从 Foo 到 Bar 的转换。前一种方案需要匹配方向有实际依据;后一种需要显式转换,Haskell 不会自动将一种类型转换成另一种类型。

关于零成本

Pattern synonym 本身不保证“零成本”。用四元组构造函数闭包仍需执行相应的构造逻辑,并生成 Bar 所需的函数值。如果目标是避免额外分配一个 Foo 值,可以直接用构造 Bar 的函数;具体运行时成本仍取决于实际表示和编译结果。

备注:内容仅供参考。