You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否实现类型为`a -> <pattern> -> Bool`的模式匹配函数?

模式匹配函数matches的可行性与实现

这种实现完全可行,但得借助Haskell的元编程扩展——因为Haskell的模式是静态语法元素,不是可以直接传递的一等公民,标准Haskell里没法直接把模式当参数传给函数。

为什么直接写xs matches [_]不行

在普通Haskell代码里,[_]是模式匹配语法,不是合法的表达式。编译器会把它当成一个包含未绑定变量_的列表字面量,直接这么写会报错——毕竟下划线在表达式里只能用来忽略变量,不能代表“任意元素”的模式。

用Template Haskell实现matches

Template Haskell是Haskell的元编程工具,能在编译阶段把模式转换成对应的匹配函数,完美解决这个问题。具体步骤如下:

  1. 先启用Template Haskell扩展,导入相关模块:
{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH
  1. 写一个模板函数,把输入的模式转换成判断值是否匹配的函数:
-- 接收模式的AST,生成返回Bool的匹配函数
mkMatcher :: PatQ -> ExpQ
mkMatcher pat = [| \x -> case x of
                          $pat -> True
                          _    -> False |]
  1. 定义matches中缀函数,用来把值和匹配函数结合:
matches :: a -> (a -> Bool) -> Bool
matches = flip ($)
  1. 现在就能按需求改写isSingleton了——用$(...)在编译时把模式[_]转成匹配函数:
isSingleton :: [a] -> Bool
isSingleton xs = xs `matches` $(mkMatcher [p| [_] |])

嫌麻烦的话,也可以直接生成isSingleton函数,不用绕matches:

isSingleton :: [a] -> Bool
isSingleton = $(mkMatcher [p| [_] |])

不用元编程的替代方案:泛型匹配

要是不想碰Template Haskell,也可以用Haskell的Generic类型类,把值和模式都转成泛型结构来对比。这种方式不用元编程,但得给类型加Generic实例,而且模式的表达能力受限于泛型结构:

{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics

-- 定义列表的模式结构
data ListPattern a = Single a | Multiple a (ListPattern a) | Empty
  deriving (Generic, Eq)

-- 把普通列表转成模式结构
listToPattern :: [a] -> ListPattern a
listToPattern [] = Empty
listToPattern [x] = Single x
listToPattern (x:xs) = Multiple x (listToPattern xs)

-- 实现泛型层面的匹配
matches :: (Generic (ListPattern a), Eq (Rep (ListPattern a) ())) => [a] -> ListPattern a -> Bool
matches xs pat = to (listToPattern xs) == to pat

-- 使用示例:用Single undefined代表单元素列表模式
isSingleton xs = xs `matches` Single undefined

不过这种方式需要手动定义模式结构,不如Template Haskell贴近原生的模式语法。

内容的提问来源于stack exchange,提问作者Good Night Nerd Pride

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 14:05:30