【问题标题】:Haskell - Pattern Matching form (x:y:zs)Haskell - 模式匹配形式 (x:y:zs)
【发布时间】:2017-05-08 08:52:30
【问题描述】:

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

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

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 该怎么做的守卫?

【问题讨论】:

    标签: haskell pattern-matching


    【解决方案1】:

    您在函数定义级别进行模式匹配。按照您的描述方式,您仅涵盖字符串长度至少为两个字符的情况:

    myFun str@(f:s:rst)
    

    您还需要处理其他情况。你可以有一个像这样的包罗万象的处理程序(需要作为最后一个模式):

    myFun _ = ...
    

    或者如果你想处理空字符串,像这样(在包罗万象之前):

    myFun [] = ...
    

    至于你的函数的目的,你最好只使用模式匹配而不是使用守卫。

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

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

    【讨论】:

    • 这行得通 - 实际上有多种更简单/更好的方法可以做到这一点。我在这里真正苦苦挣扎的是试图弄清楚如果无法通过提供的模式解构参数,是否有办法告诉警卫该怎么做。我是否应该将您的回答理解为:“是的,如果您在函数声明中定义模式,则在使用警卫时这是不可能的”
    • 函数级别的模式匹配首先发生,这意味着你所拥有的前两个保护条件永远不可能满足(那些你检查 str 的长度为零或一个长度的条件)
    【解决方案2】:

    根据 Chad Gilbert 的特别有用的回答和一些额外的修改, 我找到了一种吃蛋糕的方法。 万一有人遇到类似的绊脚石,这里有一种方法可以在声明您的警卫之前指定未发现的案例:

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

    这也适用于多个参数:

    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 的人来说可能非常明显,但我没有意识到你被“允许”使用不同的语法多次声明函数以涵盖不同的情况。

    【讨论】:

    • 只是为了好玩,您可能还喜欢:lastTwo = reverse . take 2 . reverse.
    猜你喜欢
    • 1970-01-01
    • 2017-11-13
    • 2021-05-22
    • 1970-01-01
    • 1970-01-01
    • 2019-03-01
    • 2016-10-29
    • 2017-10-12
    • 2011-11-30
    相关资源
    最近更新 更多