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

Haskell中parse函数未显式用参数却能运行的原因探究

关于Haskell逆波兰式正则表达式转表达式树代码的疑问解答

我参考了Stack Overflow上相关问题的回答,代码如下:

data Tree
  = Symbol Char
  | Op Char Tree Tree
  deriving Show

type Stack = [Tree]

step :: Stack -> Char -> Stack
step (r:l:s) '.' = (Op '.' l r):s
step (r:l:s) '+' = (Op '+' l r):s
step s c         = (Symbol c):s

parse :: String -> Stack
parse = foldl step []

将这段代码放入文件并添加main函数调用parse "aa.bb.+"后,得到了和原问题一致的结果,但我有两个疑问:

  • parse函数没有显式使用第一个待解析的参数,为什么能正常运行?
  • step函数是如何接收第二个参数的?
    另外,我把parse的定义改成parse s = foldl step [] s后,程序也能正常运行,这样写法看起来更合理,因为parse现在显式使用了参数。

问题解答

这本质是Haskell的**柯里化(Currying)**特性在起作用:

  • 先看foldl的类型:foldl :: (b -> a -> b) -> b -> [a] -> b。当我们写foldl step []时,相当于已经给foldl传了前两个参数(step和初始栈[]),此时它会返回一个类型为[a] -> b的函数——这里a对应Char,b对应Stack,正好匹配parse :: String -> Stack的类型要求。所以parse = foldl step []其实是parse s = foldl step [] s的简写,Haskell会自动补全最后一个参数,这种省略最后参数的写法叫部分应用。
  • 关于step的参数传递:foldl会遍历输入的字符串(也就是"aa.bb.+"),每次取出一个字符,把当前的栈状态和这个字符作为参数传给step,step处理后返回新的栈,foldl再用这个新栈继续处理下一个字符,直到遍历完所有字符。所以step的第二个参数就是foldl遍历字符串时逐个传入的字符。

两种写法(parse = foldl step []和parse s = foldl step [] s)是完全等价的,前者是Haskell中更简洁的惯用写法,后者则更直观地展示了参数传递过程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 13:48:22