>我有以下代码:
{-
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)