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

为何无法用美元符号($)替代Haskell代码中的括号?

用$替代Haskell groupElems函数中的括号:问题解析与解决方案

首先,先看你这段可以正常运行的分组函数:

groupElems :: Eq a => [a] -> [[a]]
groupElems [] = []
groupElems (x:xs) = (fst spaned) : groupElems (snd spaned)
  where spaned = span (== x) (x:xs)

它的运行效果符合预期:

groupElems [1,2,2,2,4] -- 输出 [[1],[2,2,2],[4]]

你尝试用$替换括号后的代码出现了类型错误,问题出在Haskell的运算符优先级上:

-- 你修改后的错误代码
groupElems :: Eq a => [a] -> [[a]]
groupElems [] = []
groupElems (x:xs) = (fst spaned) : groupElems $ snd spaned
  where spaned = span (== x) (x:xs)

编译器报错的核心原因是:$的优先级是Haskell里最低的,远低于列表拼接运算符:。所以这段代码会被解析成:

((fst spaned) : groupElems) $ snd spaned

而(fst spaned) : groupElems的类型是[[a]],它是一个值,不是能接收参数的函数——但$要求左边必须是一个函数,右边是它的参数,这就导致了类型不匹配的错误。

正确的$用法

当然可以用$来简化括号,只是要注意优先级的影响,有两种合理的修改方式:

方式1:给groupElems $ snd spaned加括号

让:的右边明确是groupElems作用于snd spaned的结果:

groupElems :: Eq a => [a] -> [[a]]
groupElems [] = []
groupElems (x:xs) = (fst spaned) : (groupElems $ snd spaned)
  where spaned = span (== x) (x:xs)

方式2:在where子句中用$替代括号

其实更简洁的是把$用在span的调用上,这里原本的括号可以直接替换:

groupElems :: Eq a => [a] -> [[a]]
groupElems [] = []
groupElems (x:xs) = (fst spaned) : groupElems (snd spaned)
  where spaned = span (== x) $ x:xs

如果想要进一步简化,还可以去掉(fst spaned)的括号(因为函数应用优先级高于:,完全没问题):

groupElems :: Eq a => [a] -> [[a]]
groupElems [] = []
groupElems (x:xs) = fst spaned : groupElems (snd spaned)
  where spaned = span (== x) $ x:xs

总结一下:$是个非常好用的括号替代工具,但一定要记住它的优先级规则——它会让右边的所有内容作为左边函数的参数,所以当它和其他高优先级运算符配合时,要确保解析顺序符合你的预期。

内容的提问来源于stack exchange,提问作者aryndin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:09:09