【问题标题】:Haskell Function Giving Wrong OutputHaskell 函数给出错误的输出
【发布时间】:2018-04-14 00:15:15
【问题描述】:

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

所以我有这个:

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

现在它适用于字符串的第一个字母,就像我将 betweenAF "all" 放入,但如果我放入 betweenAF "lla" 则不起作用。谁能告诉我我做错了什么以及如何解决它?

【问题讨论】:

  • 它不起作用:betweenAF "all" 在应该是False 时返回True
  • betweenAF "lla" 按预期产生falseideone.com/E54So5
  • (x:y:xs) 只匹配长度为 2 或以上的字符串;您的 _ 案例捕获所有单例列表空列表,并非所有列表都应具有相同的返回值。

标签: string list function haskell recursion


【解决方案1】:

该功能有效。只是,它的作用是:它查看'a'..'f' 中是否存在 any 偶数索引元素。而您显然希望它查看 所有 元素是否在范围内。

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

【讨论】:

    【解决方案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 [] 都计算为[]

    【讨论】:

    • 你错过了| otherwise,但否则(鼓声)完美。
    • 我忽略了它,因为我将“x不在列表中”与“(x:y:xs)不匹配”混为一谈。当然,然后我忘了处理空列表,然后我单独添加了它,所以我要花点时间来决定这是否比明确的 otherwise...
    • 我认为忽略 else 是不正确的,不是吗?如果模式匹配但没有守卫匹配,Haskell 会做什么?
    • 我不太喜欢重复的elem 测试,但它肯定不会比我拥有的更糟糕
    • betweenAF [] = True; betweenAF (x:ys) = (x `elem` ['a'..'f']) && betweenAF (drop 1 ys) 怎么样。
    【解决方案3】:

    仅仅因为我花了几分钟时间,我想指出另一种可能的解决方案。您可以提取每个其他字符并使用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 -&gt; elem x ['a'..'z']。总而言之,这可以重写为:

    betweenAF = all (flip elem ['a'..'z']) . map snd . filter fst . zip (cycle [True, False])
    

    然而,这比罪还要丑陋!

    【讨论】:

    • 对我来说,使用(`elem` ['a'..'z']) 会使最后一个变体更容易忍受,甚至可以接受。
    【解决方案4】:

    只是为了一些练习,我猜你也可以这样做;

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-08
      • 1970-01-01
      • 2021-02-11
      相关资源
      最近更新 更多