【问题标题】:Pattern matching list is failing模式匹配列表失败
【发布时间】:2019-06-22 13:48:12
【问题描述】:

我有以下代码:

{-
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

我在这里做错了什么?

【问题讨论】:

  • last x是一个非total函数,在非空列表上会出错。
  • 最后一个子句的名称 (concatBackslash) 也不同于上面的子句名称 (concatOnBackslash)。
  • 启用警告指出最后一行的拼写错误,因为那将是一个没有类型签名的函数。
  • 感谢您的提示 :)

标签: string list haskell


【解决方案1】:

这确实是正确的。第一个问题是您的最后一个子句定义了一个函数concatBackslash,而其他子句定义了一个函数concat<b>On</b>Backslash(带有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] -&gt; a(和init :: [a] -&gt; [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)

【讨论】:

  • 但是,当我在空白处拆分字符串时,是否不可能得到一个空列表?
  • @Biskit1943: 不,例如splitOn " " " b",你会得到["", "b"],或splitOn " " "a b" == ["a", "", "b"]。也许处理这样的字符串是奇怪的,但是*比抱歉更安全" :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-15
  • 2018-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-05
相关资源
最近更新 更多