如何创建判断列表是否为另一列表子列表的布尔返回函数?字符列表适配问题及解决
解决Haskell子列表判断函数对字符串失效的问题
这真是个容易踩的模式匹配顺序坑!我来帮你拆解下问题出在哪,以及为什么调换基准条件顺序就能解决。
首先回顾下你的场景:你想要实现一个函数,判断列表x是否是y的子列表,比如['a','b']在['c','d','a','b']中应该返回True。你最初写的函数对数字列表工作正常,但处理字符串(本质是字符列表)时却意外返回False:
原函数代码:
check x y = aux x x y aux _ _ [] = False aux _ [] _ = True aux x (h:t) (j:k) |h==j= aux x t k |otherwise= aux x x k
测试情况:
- 正常工作:
check [1,2] [1,3,1,5,1,2,7]返回True - 失效场景:
check "ab" "cdab"返回False,但目标字符串明明包含"ab"
好在你已经通过调换两个基准条件的顺序修复了问题,修复后的代码如下:
check x y = aux x x y aux _ [] _ = True aux _ _ [] = False aux x (h:t) (j:k) |h==j= aux x t k |otherwise= aux x x k
问题根源:模式匹配的顺序优先级
Haskell的模式匹配是从上到下依次匹配的,哪个模式先匹配到就执行对应的分支。原函数的问题出在这两个基准条件的顺序上:
当我们检查check "ab" "cdab"时,遍历到目标列表的最后两个字符时会经历这些步骤:
- 匹配
'a' == 'a',调用aux "ab" "b" "b" - 接着匹配
'b' == 'b',调用aux "ab" [] []
这时候原函数的第一个基准条件aux _ _ [] = False会先被触发——因为它排在aux _ [] _ = True前面,程序直接返回False,但实际上此时子列表已经完全匹配完成(第二个参数是空列表),应该返回True才对!
而修复后的函数把aux _ [] _ = True放在了前面,当aux "ab" [] []被调用时,会优先匹配到这个分支,正确返回True,问题自然就解决了。
顺便提一句:这个问题其实和处理数字还是字符无关,只是你测试数字的场景中,匹配完成时目标列表还没到末尾,所以没触发这个顺序问题。比如你用原函数测试check [1,2] [3,1,2],同样会返回False,原理和字符串的情况完全一样。
内容的提问来源于stack exchange,提问作者Heil
相关产品推荐
相关产品推荐

