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
相关产品推荐
相关产品推荐

