GHC接受疑似非法的波浪号语法?求解析背后逻辑
为什么GHC会接受
~ x = x + 2这种看似非法的代码? 咱们直接说结论:这段代码里的~其实是完全多余的冗余语法,GHC最终会把它解析成普通的递归变量定义x = x + 2——这就是你运行x时会无限循环的原因。
接下来咱们一步步拆解:
1. 不可辩驳模式(~)的本来用途
不可辩驳模式(用~标记)是用来在函数参数或复杂模式绑定里跳过匹配检查的。比如:
f ~(a, b) = a + b
调用f undefined时,不会因为undefined不是元组而报错,而是直接让a和b绑定到底层值(bottom),最终求值a + b才会触发错误。
但对于单个变量来说,不可辩驳模式毫无意义:变量模式本身就能匹配任何值,永远不会失败。所以~x作为模式,和直接写x是完全等价的。
2. GHC对~ x = x + 2的解析逻辑
Haskell允许顶层定义使用模式绑定(比如(x, y) = (1, 2)),当你写~ x = x + 2时:
- 左边的
~x被解析成一个不可辩驳的变量模式,和x没有区别; - 右边的
x + 2引用了这个变量本身,形成了递归定义。
这就和你直接写x = x + 2一模一样——因为没有终止条件,求值x时会无限递归,永远停不下来。
3. 对比合法的中缀运算符定义
你提到的~ x +++ y = y * 3是完全合理的:
- 这是中缀运算符
(+++)的定义,第一个参数用了不可辩驳模式~x; - 这里的
~确实发挥了作用:如果调用undefined +++ 5,不会因为undefined无法匹配而立刻报错,而是直接返回5*3=15(因为不可辩驳模式跳过了对第一个参数的匹配检查)。
4. 关于:i ~和:i (~)的疑惑
- 输入
:i ~报错,是因为~不是合法的标识符,GHC的:info命令需要你传入一个符合规则的名称; - 输入
:i (~)查到的Data.Type.Equality.(~)是类型层面的类型相等约束,和你这里在 term 层面用的模式匹配符号~完全是两个独立的东西,没有任何关联。
5. 为什么无法自定义(~)运算符?
GHC把~作为内置的模式匹配语法符号,属于保留字范畴,所以你不能把它定义成自定义运算符或类——这就是你看到“Illegal binding of built-in syntax”错误的原因。
内容的提问来源于stack exchange,提问作者AntC
相关产品推荐
相关产品推荐

