Haskell函数给出错误的输出

时间:2017-11-01 16:00:23

标签: string list function haskell recursion

我有这个提示:创建一个带字符串的函数,看看是否所有其他字母都是['a'...'f']的元素

所以我有这个:

betweenAF :: String -> Bool
betweenAF (x:y:xs)  
    | x `elem` ['a' .. 'f'] = True
    | otherwise = betweenAF xs
betweenAF _ = False

现在它可以在字符串的第一个字母上工作,就像我把它放在AF“all”之间,但是如果我放在AF“lla”之间它就不起作用。有人能告诉我我做错了什么以及如何解决它?

4 个答案:

答案 0 :(得分:2)

该功能有效。就是这样做:它会看到 是否存在'a'..'f'中的任何偶数索引元素。而您显然希望它能够看到所有元素是否在范围内。

应用简单的逻辑反转来解决这个问题。

答案 1 :(得分:2)

你的情况有所逆转。如果x 范围内,那么您只能完成部分工作并且必须递归。如果范围内的x ,您可以立即返回False,因为其他字母是否在范围内无关紧要。对于空列表,该属性是真空的,因为没有不在期望范围内的字母。

betweenAF :: String -> Bool
betweenAF [x] = betweenAF [x,x] -- hack to handle odd-length lists
betweenAF (x:y:ys) | x `elem` ['a'..'f'] = betweenAF ys
                   | otherwise = False
betweenAF [] = True

更好的版本,感谢Will Ness:

betweenAF (x:xs) = x `elem` ['a'..'f'] && betweenAF (drop 1 xs)
betweenAF [] = True

因为drop 1 [x]drop 1 []都评估为[]

答案 2 :(得分:1)

仅仅因为我花了几分钟时间,我想指出另一种可能的解决方案。您可以拉出所有其他字符,而不是对整个字符串进行模式匹配,并使用all根据谓词检查所有字符。这消除了进行任何显式递归或模式匹配的需要。

betweenAF :: String -> Bool
betweenAF = all (flip elem ['a'..'z']) . everyOther where
  everyOther xs = [v | (k,v) <- zip (cycle [True, False]) xs, k]

everyOther相当于map snd . filter (fst) . zip (cycle [True, False])flip elem ['a'..'z']相当于\x -> elem x ['a'..'z']。总而言之,这可以重写为:

betweenAF = all (flip elem ['a'..'z']) . map snd . filter fst . zip (cycle [True, False])
然而,这比罪恶更加丑陋!

答案 3 :(得分:1)

对于某些练习,我猜你也可以这样做;

everyOtherInAF :: String -> Bool
everyOtherInAF = all id . zipWith ($) (cycle [(`elem` ['A'..'F']), const True])

*Main> everyOtherInAF "AsErCgHm"
False
*Main> everyOtherInAF "AsErCgFm"
True
*Main> everyOtherInAF "AsErjgFm"
False
*Main> everyOtherInAF "AsErAgFm"
True