Reputation: 619
I have the following Code:
{-
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)
Which compiles and should return me a list of Strings splitted at a non escaped white-space.
However the following happens:
*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
What am I doing wrong here?
Upvotes: 1
Views: 55
Reputation: 477230
This is indeed correct. The first problem is that your last clause defines a function concatBackslash
, whereas the other clauses define a function concatOnBackslash
(with On
). This thus means that Haskell considers this two different functions. You can rename these to:
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)
Now the test case will work, but the function is still not very safe.
The last :: [a] -> a
(and init :: [a] -> [a]
) functions are non-total. For an empty list, these fail:
Prelude> last []
*** Exception: Prelude.last: empty list
Prelude> init []
*** Exception: Prelude.init: empty list
This thus means that concatOnBackslash
thus will error, given the first element is empty, like:
Prelude Data.List.Split> concatOnBackslash ["", "a"]
*** Exception: Prelude.last: empty list
You thus better use pattern matching here, like:
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)
Upvotes: 2