我试图写一个函数detadj :: String -> Bool
,它需要一个字符串并返回true if字符串包含两个相邻的相同字符。例如:
detadj "" == False
detadj "s" == False
detadj "ss" == True
detadj "Misisipi" == False
detadj "Mississippi" == True
detadj "single-dash" == False
detadj "double--dash" == True
我有两个版本的函数,一个在列表推导中,在许多情况下是错误的,但最常见的是当detadjlc ["ss"]
由于使用(x:y:xs)
位而输出空列表时:
detadjlc :: String -> Bool
detadjlc [] = False
detadjlc [x] = False
detadjlc (x:y:xs) = head[ x == y && isAlpha x == isAlpha y | (x,y) <- zip (x:y:xs) xs ]
和递归(这在输入是detadjr [" ee"]
时不起作用,它产生False
而不是True
):
detadjr :: String -> Bool
detadjr [] = False
detadjr [x] = False
detadjr (x:y:xs) | x == y = True
| otherwise = d xs
有哪些方法可以解决这些问题?
下面是一个使用列表推导式的迭代解。我们创建一个包含输入列表相邻元素的元组列表。然后比较元组中的元素。
detadjlc :: String -> Bool
detadjlc xs = or [x == y | (x, y) <- zip xs (tail xs)]
递归解决方案最好按照@chepner已经发布的方法完成。
您的递归函数很好,除了一个小细节:您忘记将y
放回递归调用的列表中。(我认为d
是detadjr
的错别字。)仅仅因为x
和y
不同,并不意味着y
和xs
的第一个字符可能不相同。
detadjr :: String -> Bool
detadjr (x:y:xs) = (x == y) || detadjr (y:xs)
detadjr _ = False
(如果您先检查两个或两个以上字符的字符串,那么单例列表和空列表可以折叠成一个基本情况。)