I am new to Haskell and took it upon myself to make a simple generic list-splitting (e.g. string-splitting) function:
-- Helper for splitting: reduce into a list of lists, splitting on delimiters
splitInner :: (Eq a) => [a] -> a -> [[a]] -> [[a]]
splitInner c s (x:y)
| s `elem` c = [] : (x:y)
| otherwise = (s : x) : y
splitInner c s []
| s `elem` c = []
| otherwise = [[s]]
-- Split a list into a list of lists on a given set of delimiters
split :: (Eq a) => [a] -> [a] -> [[a]]
split delim = foldr (splitInner delim) []
-- Remove empty lists from a list of lists
collapse :: (Eq a) => [[a]] -> [[a]]
collapse = filter (/= [])
-- Split a string on any span of whitespace within
splitSpaces = collapse . split "\t\r\n "
main = (print . splitSpaces) "\t \r\nhello world, this is code!\nFoo bar "
-- prints ["hello", "world,", "this", "is", "code!", "Foo", "bar"]
I'm aware that there's a split
package that already implements functionality like this.
However, I'm curious: is there any way I could have expressed this functionality better, or more concisely or clearly, still using just the standard library? Or, perhaps, does my code deviate from a typical Haskell solution in some other way? I'm much more used to imperative than functional programming and don't yet have the best sense on evaluating the 'readability' or clarity of code like this.
I'd also like to point out the fact that I couldn't figure out a good way to clearly label the arguments to a function in its definition - the signature [a] -> [a] -> [[a]]
certainly doesn't reveal which [a]
is the delimiter, for example.