如何使用像给定单词的第n个字母等条件等于另一个单词的第m个字母来模式匹配?

时间:2016-12-13 15:41:55

标签: haskell pattern-matching

给出一个像[“hello”,“pale”,“joke”,“okay”]这样的单词列表,如何将以下语句转换为Haskell代码?

  

给我列表中的单词集,使第一个单词的第二个字母等于第二个单词的第一个字母。

在这种情况下,答案是[“笑话”,“好的”],因为字母“o”满足条件。一般来说,我如何指定我需要一组单词,其中一个单词的第n个字母等于另一个单词的第m个字母。

此外,我怎样才能将这个概念扩展到多个单词,例如,给我一组单词,其中第一个单词的第四个字母等于第二个单词的第三个字母,第一个单词的最后一个字母等于第一个单词第三个字的字母。给定列表的结果应该是[“你好”,“苍白”,“好的”]。

1 个答案:

答案 0 :(得分:3)

第一个用例在Haskell中很容易解决,首先需要配对连续的单词:

pairs :: [String] -> [(String, String)]
pairs wrds = zip wrds $ drop 1 wrds

然后编写逻辑以匹配第一个单词的第二个字母和第二个单词的第一个字母,非常简单的模式匹配:

secondLetterMatchesFirstLetter :: String -> String -> Bool
secondLetterMatchesFirstLetter (_:a:_) (b:_) = a == b
secondLetterMatchesFirstLetter _ _ = False

最后将这些结合在一起:

matchingWords :: [String] -> [(String, String)]
matchingWords = filter (uncurry secondLetterMatchesFirstLetter) . pairs

对于任何第m和第n个字母执行此操作需要一些额外的参数以及使用更一般的函数交换secondLetterMatchesFirstLetter,让我们先写一下:

mthMatchesNth :: Int -> Int -> String -> String -> Bool
mthMatchesNth m n first second = (first `safeIdx` m) == (second `safeIdx` n)
    where
        -- Note: this isn't efficient
        safeIdx [] n = Nothing
        safeIdx (x:_) 0 = Just x
        safeIdx (_:rest) n = safeIdx rest (n - 1)

matchingWords :: Int -> Int -> [String] -> [(String, String)]
matchingWords m n = filter (uncurry $ mthMatchesNth m n) . pairs

将此扩展到任意分组单词的工作会稍微复杂一点,我会让你自己解决这个问题。此代码应该帮助您了解如何进行匹配,特别是因为您无论如何都能够重用mthMatchesNth函数。我会考虑使用数据类型来表示这个问题,因为只是传递一些Int会使得很难跟上细节。