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

如何为使用中缀运算符的数据构造器添加额外参数?

解决带位置参数的中缀数据构造器问题

首先明确报错原因:你的写法Expr :*: Expr Pos会被GHC优先解析为Expr :*: (Expr Pos),但Expr的kind是*(普通类型),不是接受参数的类型构造器* -> *,所以无法像Expr Pos这样使用,导致报错。

中缀数据构造器在Haskell中只能是二元的(即接受两个参数),所以无法直接定义带第三个位置参数的中缀构造器,但有两种方案可以接近你的需求,同时保留中缀的构造和模式匹配风格:

方案一:前缀定义三元构造器,声明为中缀

先给构造器声明中缀优先级,再定义带位置参数的三元构造器:

infixl 7 :*:  -- 和原来的优先级保持一致
data Expr = IntL Integer Pos | (:*:) Expr Expr Pos

构造表达式

可以用前缀形式,或者利用中缀语法结合括号:

-- 前缀写法
(:*:) (IntL 10 pos1) (IntL 20 pos2) pos3

-- 中缀写法(GHC会正确解析位置参数为构造器的第三个参数)
(IntL 10 pos1) :*: (IntL 20 pos2) pos3

模式匹配

可以用前缀形式,或者更贴近中缀的风格:

eval :: Expr -> Integer
eval (IntL n _) = n
-- 前缀模式匹配
eval ((:*:) e1 e2 _) = eval e1 * eval e2
-- 中缀风格模式匹配(用反引号包裹构造器)
eval (e1 `:*:` e2 _) = eval e1 * eval e2

这种方式完全保留了:*:的中缀语义,只是在构造和匹配时需要处理第三个位置参数,是最接近你需求的方案。

方案二:将位置参数整合为构造器的一部分

如果不想用三元构造器,可以把位置参数作为中缀构造器的左操作数,重新定义构造器:

infixl 7 @*@
data Expr = IntL Integer Pos | Pos @*@ (Expr, Expr)

构造与匹配

-- 构造
pos3 @*@ (IntL 10 pos1, IntL 20 pos2)

-- 匹配
eval (pos @*@ (e1, e2)) = eval e1 * eval e2

这种方式语法更直观,但和原有的:*:写法差异稍大。

为什么你的尝试失败?

  • (Expr :*: Expr) Pos:Haskell不支持这种将中缀表达式作为类型构造器的写法,类型层面的中缀语法仅适用于二元类型构造器。
  • 前缀形式(:*:) Expr Expr Pos:这个定义本身是合法的,你觉得无法用相同方式模式匹配,是因为没掌握中缀模式的写法——用反引号包裹构造器即可实现中缀风格的匹配。

内容的提问来源于stack exchange,提问作者Lucas Buhl-Nielsen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 15:25:23