Haskell与PureScript中$运算符差异、相关类型规则及对runST的影响
GHC 针对$运算符的特殊类型规则
标准 Haskell 中$运算符的默认类型签名为:
($) :: (a -> b) -> a -> b
受限于标准 Hindley-Milner 类型系统的谓词限制(不允许将类型变量实例化为带forall量词的多态类型),普通的$函数无法处理接收秩2及以上多态参数的场景。GHC 为$添加的特殊类型规则本质是:对f $ x做类型检查时,直接等价于检查f x的类型,不会将$作为普通二元函数处理,会完整保留右参数x的多态性(包括嵌套的类型量词)传递给左函数f,不需要提前将右参数的类型具象化。
该规则对runST调用的影响
runST是典型的秩2类型函数,它的类型签名为:
runST :: forall a. (forall s. ST s a) -> a
它要求传入的参数必须是对任意状态标记s都有效的ST s a类型值(参数位置的嵌套forall s就是强制该参数的多态性)。
如果$是普通函数:
- 类型推导时会尝试将
$的类型参数a匹配为do块的类型,而默认规则不允许将a实例化为带forall s的多态类型,会提前把do块的s具象为某个固定类型,最终导致参数类型和runST的要求不匹配,报类型错误。
而 GHC 的特殊规则生效时: runST $ do ...的类型检查逻辑和runST (do ...)完全一致,do块的完整多态类型会被保留,刚好匹配runST要求的秩2参数类型,因此可以正常通过类型检查。
PureScript 没有为$实现这个特殊规则,$就是普通的二元函数,因此runST $ do ...会触发类型错误,只能选择无运算符的runST do ...或者括号包裹的runST (do ...)写法绕开这个限制。
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

