Haskell 模式不匹配 [_]

Ama*_*eur 2 string haskell list pattern-matching

我一直在尝试使以下代码工作:

{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
import Data.List
format :: String -> String
format [] = []
format (a:b:xs)
 | a == 'W' && b == 'U' = " " ++ format (drop 1 xs) 
 | otherwise = a : format (b:xs)

songDecoder :: String -> String
songDecoder xs = unwords. words . format $ xs
Run Code Online (Sandbox Code Playgroud)

当我测试时:

歌曲解码器“AWUBBWUBC”

我希望“ABC”作为输出。但是,我收到了一个不寻常的模式匹配警告:

Pattern match(es) are non-exhaustive
In an equation for ‘format’: Patterns not matched: [_]
Run Code Online (Sandbox Code Playgroud)

我不确定为什么我需要匹配 [_]

format (a:b:xs)
Run Code Online (Sandbox Code Playgroud)

请帮忙。

Wil*_*sem 5

就像@EricFulmer在他的回答中所写的那样,(a:b:xs)匹配具有两个或多个项目的列表。所以你的功能是这样的:

format [] = ...       -- empty list
format (a:b:xs) = ... -- two or more
Run Code Online (Sandbox Code Playgroud)

Haskell 警告说,包含一个元素的列表[_]将不匹配这些行中的任何一行:两种模式都将失败。

因此,您应该添加一个子句,以指定在列表包含一个元素的情况下应该发生什么,例如(并且可能):

format a@[_] = a
Run Code Online (Sandbox Code Playgroud)

where@别名运算符,它与一个只有一个元素的列表绑定。

然后我们得到:

format :: String -> String
format [] = []
format a@[_] = a
format (a:b:xs)
 | a == 'W' && b == 'U' = " " ++ format (drop 1 xs) 
 | otherwise = a : format (b:xs)
Run Code Online (Sandbox Code Playgroud)

通过将比较移动到模式匹配中,我们可以使函数更优雅:

format :: String -> String
format [] = []
format a@[_] = a
format ('W':'U':xs) = format $ drop 1 xs 
format (a:b:xs) = a : format (b:xs)
Run Code Online (Sandbox Code Playgroud)

现在最后一种情况可以简化为:

format (a:xs) = a : format xs
Run Code Online (Sandbox Code Playgroud)

现在第二个子句(our format a@[_])变得过时了,因为最后一个子句也处理这种情况。所以我们把函数变成:

format :: String -> String
format [] = []
format ('W':'U':xs) = format $ drop 1 xs 
format (a:xs) = a : format xs
Run Code Online (Sandbox Code Playgroud)

就我个人而言,我认为这更优雅,因为在这里很清楚您的目标是与第二个模式匹配(您不必编写一系列条件)。此外,几乎可以从语法上看出该函数处理所有可能的输入。