模式匹配列表失败



>我有以下代码:

{-
Returns a list of Strings splitted by ' '. '\ ' is kept as ' '
-}
splitOnWhitespace :: String -> [String]
splitOnWhitespace s = concatOnBackslash $ splitOn " " s
{-
concats Strings on '\' with a whitespace
-}
270 concatOnBackslash :: [String] -> [String]
271 concatOnBackslash [] = []
273 concatOnBackslash [x] = [x]
274 concatOnBackslash [x, xs] = case last x of
275     '\' -> [(init x) ++ " " ++ xs]
276     _ -> [x, xs]
277 concatBackslash (x : xx : xs) = case last x of
278     '\' -> concatOnBackslash (((init x) ++ " " ++ xx) : xs)
279     _ -> x: concatOnBackslash (xx : xs)

它编译并应该向我返回一个在非转义空格处拆分的字符串列表。

但是,会发生以下情况:

*Filesystem> splitOnWhitespace "a1"
["a1"]
*Filesystem> splitOnWhitespace "a1 a2"
["a1","a2"]
*Filesystem> splitOnWhitespace "a1 a2 a3"
*** Exception: src/Filesystem.hs:(271,1)-(275,24): Non-exhaustive patterns in function concatOnBackslash
*Filesystem> splitOnWhitespace "a1 a2 a3 a4"
*** Exception: src/Filesystem.hs:(271,1)-(275,24): Non-exhaustive patterns in function concatOnBackslash

我在这里做错了什么?

确实是正确的。第一个问题是最后一个子句定义了一个函数concatBackslash,而其他子句定义了一个函数concatOnBackslash(带On(。因此,这意味着Haskell考虑了这两个不同的功能。您可以将这些重命名为:

concatOnBackslash :: [String] -> [String]
concatOnBackslash [] = []
concatOnBackslash [x] = [x]
concatOnBackslash [x, xs] = case last x of
    '\' -> [(init x) ++ " " ++ xs]
    _ -> [x, xs]
concatOnBackslash (x : xx : xs) = case last x of
    '\' -> concatOnBackslash (((init x) ++ " " ++ xx) : xs)
    _ -> x: concatOnBackslash (xx : xs)

现在测试用例可以工作了,但功能仍然不是很安全。

last :: [a] -> a (和init :: [a] -> [a](函数是非总计的。对于空列表,这些失败:

Prelude> last []
*** Exception: Prelude.last: empty list
Prelude> init []
*** Exception: Prelude.init: empty list

因此,这意味着concatOnBackslash因此会出错,给定第一个元素为空,例如:

Prelude Data.List.Split> concatOnBackslash ["", "a"]
*** Exception: Prelude.last: empty list

因此,您最好在此处使用模式匹配,例如:

concatOnBackslash :: [String] -> [String]
concatOnBackslash [] = []
concatOnBackslash [x] = [x]
concatOnBackslash [[], xs] = ...
concatOnBackslash [x@(_:_), xs] = case last x of
    '\' -> [(init x) ++ " " ++ xs]
    _ -> [x, xs]
concatOnBackslash ([] : xx : xs) = ...
concatOnBackslash (x@(_:_) : xx : xs) = case last x of
    '\' -> concatOnBackslash (((init x) ++ " " ++ xx) : xs)
    _ -> x: concatOnBackslash (xx : xs)

最新更新