Haskell代码中模式匹配y参数作用及改写后结果差异问题
Haskell 列表模式匹配问题解答
首先贴出问题涉及的原可运行代码:
f [] = [] f [x] = [x] f (x:y:xs) = x : f xs main = print (f [0,5..50]) -- 运行输出: [0,10,20,30,40,50]
第三行中y参数的作用
Haskell列表模式匹配遵循从上到下优先级匹配、按模式结构拆分列表的规则:
(x:y:xs)这个模式仅匹配长度≥2的列表:拆分后x绑定列表第1个元素,y绑定列表第2个元素,xs绑定列表从第3个元素开始的剩余子列表。- 这里的
y没有在等式右侧参与任何计算,核心作用有两个:- 限定分支匹配范围:只有列表剩余长度≥2时才走这个递归分支,长度为1时走
f [x] = [x]终止分支,为空时走f [] = []终止分支。 - 实现跳过元素的逻辑:因为模式已经把第二个元素划归到
y的绑定位置,传给递归的xs是跳过前两个元素之后的子列表,相当于每次递归向前走2位,实现隔一个元素取一个的效果。
- 限定分支匹配范围:只有列表剩余长度≥2时才走这个递归分支,长度为1时走
注:这里的
y完全可以替换为通配符_(即写成f (x:_:xs) = x : f xs),运行效果完全一致,还能避免编译器抛出“定义了未使用变量”的警告,是更规范的写法。原代码写y只是刚好完成模式拆分,没有其他特殊作用。
用输入列表[0,5,10,15,20,25,30,35,40,45,50](即[0,5..50]的实际展开结果)走一遍递归流程就能直观理解逻辑:
- 初始列表长度11≥2,匹配第三分支:取x=0,丢y=5,递归处理xs=[10,15,20,25,30,35,40,45,50]
- 传入列表长度9≥2,匹配第三分支:取x=10,丢y=15,递归处理xs=[20,25,30,35,40,45,50]
- 重复上述逻辑依次取出20、30、40,直到最后传入递归的列表是[50],长度为1,匹配第二个终止分支直接返回[50]
- 所有取出的元素按顺序拼接,就得到结果[0,10,20,30,40,50]
替换为f (x:xs) = x : f xs后无法得到相同结果的原因
修改后的第三行模式(x:xs),匹配的是所有长度≥1的非空列表:拆分后x绑定列表第1个元素,xs绑定列表从第2个元素开始的剩余子列表。这个改动直接改变了递归的步长:
- 原模式每次递归消耗2个列表元素(留1个、丢1个),递归传入的是跳2位后的子列表,实现隔位取值。
- 新模式每次递归只消耗1个列表元素(留第1个),递归传入的是只跳1位的完整尾列表,相当于遍历列表时每个元素都会被取出,不会跳过任何值。
走一遍修改后的递归流程就能看到明显差异:
- 初始列表长度11≥2,匹配第三分支:取x=0,递归处理xs=[5,10,15,...50]
- 传入列表长度10≥2,匹配第三分支:取x=5,递归处理xs=[10,15,...50]
- 重复上述逻辑会依次取出0、5、10、15...直到最后取到50,最终返回的就是原列表
[0,5,10,15,20,25,30,35,40,45,50],自然和预期的隔位取值结果不同。
内容的提问来源于stack exchange,提问作者madPatatoO
相关产品推荐
相关产品推荐

