首页 文章

Haskell - 模式匹配形式(x:y:zs)

提问于
浏览 1428
1

我很难理解如何在警卫中使用模式匹配 .

我有这个示例函数,其目的是返回字符串中的最后一个字符 .

myFun :: [Char] -> Char
myFun str@(f:s:rst)
      | str == ""  = error "0 length string"
      | length str == 1 = head str
      | rst == "" = s
      | otherwise = lame (s:rst)

传递带有单个字符的字符串时,“函数中的非穷举模式”失败了 .

我假设Haskell意识到它不能使用 (f:s:rst) 形式匹配单个元素列表,然后在尝试评估对 length 的调用之前失败 .

如果只有一个元素,我如何制作一个告诉Haskell要做什么的警卫?

2 回答

  • 4

    基于Chad Gilbert特别有用的答案,以及一些额外的修修补补,我找到了一种方法来吃蛋糕并吃掉它 . 如果有人有类似的绊脚石,这里有一种方法可以在宣布你的警卫之前指明未被发现的案件:

    myFun :: [Char] -> Char
    myFun "" = ""
    myFun str@(s:rst)
          | rst == "" = s
          | otherwise = myFun (s:rst)
    

    这也适用于多个args:

    strSplit :: [Char] -> [[Char]] -> [[Char]]
    strSplit str [] = strSplit str [""]
    strSplit "" _ = [""]
    strSplit str@(s1:ns) list@(x:xs)
           | s1 == '|' = strSplit ns ("":list)
           | ns == "" = map reverse $ ((s1 : x) : xs)
           | otherwise  = strSplit ns ((s1 : x) : xs)
    

    或者使用原始 pattern@(first:second:rest) 想法的东西:

    lastTwo :: [Char]->[Char]
        lastTwo "" = ""
        lastTwo [x] = [x]
        lastTwo str@(f:s:rst)
                | rst =="" = [f,s]
                | otherwise = lastTwo (s:rst)
    

    这对于更熟悉Haskell的人来说可能是非常明显的,但是我没有意识到你被“允许”使用不同的语法多次声明函数来覆盖不同的情况 .

  • 1

    您是函数定义级别的模式匹配 . 你描述它的方式,你只是覆盖字符串长度至少为两个字符的情况:

    myFun str@(f:s:rst)
    

    您还需要处理其他情况 . 你可以像这样拥有一个全能的处理程序(需要作为最后一个模式):

    myFun _ = ...
    

    或者,如果你想处理空字符串,就像这样(在catch-all之前):

    myFun [] = ...
    

    至于你的功能的目的,你可能最好只使用模式匹配而不是使用警卫 .

    myFun :: [Char] -> Char
    myFun [] = error "empty string"
    myFun [x] = x
    myFun (x:xs) = myFun xs
    

    (请注意,返回 Maybe Char 而不是崩溃程序会更加惯用)

相关问题