为何无法用美元符号($)替代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
相关产品推荐
相关产品推荐

