# Split String by delimiter in Haskell

I wrote a split by delimiter function in Haskell and wanted some feedback on this piece of code. Since I come from an imperative programming background, I often write too complex functions in haskell.

split :: Char -> String -> [String]
split c str = fst $splitInternal c ([], str) splitInternal :: Char -> ([String], String) -> ([String], String) splitInternal _ (result, "") = (result, "") splitInternal c (result, str) = splitInternal c ( result ++ [takeWhile (/= c) str], case dropWhile (/= c) str of "" -> "" rest -> tail rest )  My questions are 1. Is it bad to have splitInternal function? I couldn't figure out a way without it. 2. Is there maybe a simpler way to write the function? 3. Any other feedback is welcome as well ## 2 Answers Is it bad to have splitInternal function? I couldn't figure out a way without it. Well, according to your procedure, I think it is necessary, but you can improve the readibility by writing some small functions and then combining them together. Besides, if there are consecutive delimiters, your split function doesn't work as expected. The code can be rewritten as following: splitInternal :: Char -> ([String], String) -> ([String], String) splitInternal _ (result, "") = (result, "") splitInternal c (result, remain) = splitInternal c (getBefore c remain, getAfter c remain) where getBefore delimiter rest = result ++ [takeWhile (/= delimiter) rest] getAfter delimiter rest = dropWhile (== delimiter) . dropWhile (/= delimiter)$ rest


Is there maybe a simpler way to write the function?

Yes, you can use the break and span function defined in Prelude:

split :: Char -> String -> [String]
split _ "" = []
split delimiter str =
let (start, rest) = break (== delimiter) str
(_, remain) = span (== delimiter) rest
in start : split delimiter remain


So in this case, your splitInternal is unnecessary.

Any other feedback is welcome as well

Well, if you are dealing with string, then a better choice is Text from Data.Text. Text is more efficient than String when you are dealing with string. In the module Data.Text, there is a pre-defined function splitOn that works almost as you expect:

ghci> :seti -XOverloadedString

ghci> splitOn "," "123,456,789"
["123","456","789"]

ghci> splitOn "," "123,,,456,789"
["123","","","456","789"]           -- This is what I mean "almost", since splitOn doesn't use the consecutive delimiters. Maybe this is what you want.
$$$$


Process a substring till the split char and then make a recursion to the rest substring

split:: Char -> [Char] -> [[Char]]

split _ [] = []
split c string |drop/="" = takeWhile (/=c) string : (split c (tail(drop)))
|otherwise =[string]
where drop = dropWhile (/=c) string

`
• Welcome to the Code Review Community. The goal of this site is to help the original poster improve their coding skills. Could you please explain why your answer is better than the original code in the question. Feb 17 at 15:38
• Welcome to Code Review! You have presented an alternative solution, but haven't reviewed the code. Please explain your reasoning (how your solution works and why it is better than the original) so that the author and other readers can learn from your thought process. Please read Why are alternative solutions not welcome? Feb 17 at 17:14