如何在Haskell中用列表推导和递归检测相邻相同字符并修复错误实现
问题背景
你需要实现detadj :: String -> Bool函数,判断输入字符串中是否存在相邻的相同字符,满足以下测试用例:
detadj "" == False detadj "s" == False detadj "ss" == True detadj "Misisipi" == False detadj "Mississippi" == True detadj "single-dash" == False detadj "double--dash" == True
列表推导版本修复
原版本存在的问题
- 模式匹配
(x:y:xs)后,zip (x:y:xs) xs的逻辑错误,例如输入"ss"时xs为空,zip结果是空列表,调用head会直接报错 - 多余添加了
isAlpha x == isAlpha y判断,不符合需求中非字母字符(如短横线)也要判断相邻相同的要求 - 用
head取列表首元素的逻辑错误,应该判断是否存在至少一个为True的结果,而非直接取第一个值
修复后的代码
detadjlc :: String -> Bool detadjlc [] = False detadjlc s = or [x == y | (x, y) <- zip s (tail s)]
修复说明
- 移除了多余的字符类型判断,只要两个相邻字符相等就算符合条件
- 用标准库内置的
or函数替代head,只要列表推导结果中存在任意一个True就返回True,空列表时or默认返回False,刚好匹配长度为1的输入场景 - 修正了zip的配对逻辑,将原字符串和去掉首字符的字符串配对,刚好拿到所有相邻的字符对
递归版本修复
原版本存在的问题
- 递归调用逻辑错误,判断
x /= y后直接传入xs递归,相当于跳过了y和xs首字符的比较,例如输入" ee"时,第一次比较空格和e不相等,直接传入["e"]进入边界分支返回False,遗漏了后面两个e的比较 - 递归调用的函数名写错,原代码写的
d xs,实际应该调用自身detadjr
修复后的代码
detadjr :: String -> Bool detadjr [] = False detadjr [_] = False detadjr (x:y:xs) | x == y = True | otherwise = detadjr (y:xs)
修复说明
- 递归时传入
y:xs而非xs,保证相邻字符不会被漏判 - 修正了递归调用的函数名,逻辑对齐需求
内容的提问来源于stack exchange,提问作者idontknowhowtocode
相关产品推荐
相关产品推荐

