I am trying to create a function split that can take either [Int] and Int or [Char] Char to split either a list of integers on an integer given or split a string on a character given. Ie
Main> split [1,2,3,0,4,5,0,0,7,8,9] 0
[[1,2,3],[4,5],[7,8,9]]
Main> split "Mary had a little lamb" ' '
["Mary","had","a","little","lamb"]
I've tried using Either and (Eq a) but it still doesn't seem to work. Below is what I've tried doing using class instances but I know very little about this and get the error Haskell 98 does not support multiple parameter classes
. The best way I think I'd understand it would be to use pattern matching or list comprehensions. Any help much appreciated.
class Split a where
split :: (Eq a) => [a] -> a -> [a]
instance Split [Char] Char where
split [] c = [""]
split (x:xs) c
| x == c = "" : (split xs c)
| otherwise = (x : head (split xs c)) : tail (split xs c)
instance Split [Int] Int where
split [] n = []
split (x:xs) n
| x == n = [] : (split xs n)
| otherwise = (x : head (split xs n)) : tail (split xs n)
I can get the split function to work with strings and characters but not lists of integers.
You need a polymorphic function split
split :: (Eq a) => [a]->a->[[a]]
Implementation is simple
split [] _ = [[]]
split (x:xs) c
| x == c = [] : (split xs c)
| otherwise = (x : head subSplit) : tail subSplit
where
subSplit = split xs c
EDIT I suggest different implementation.
split :: Eq a => [a] -> a -> [[a]]
split x c = map reverse $ split' x c []
where
split' :: Eq a => [a] -> a -> [a] -> [[a]]
split' [] _ a = [a]
split' (x:xs) c a
| x == c = a : split' xs c []
| otherwise = split' xs c (x:a)
Just to contribute with an other approach. This solution uses foldr
. I think it is quite neat but less undestable than @talex's
split :: (Eq a) => [a] -> a -> [[a]]
split l c = foldr f acc l
where acc = [[]]
f a t@(i@(x:_):xs) = if a == c then []:t else (a:i):xs -- Case when the current accumulator is not empty
-- | |- cons a to current accumulator
-- |- start a new accumulator
f a t@([]:xs) = if a == c then t else [a]:xs -- Case when the current accumulator is empty. Usefull when two separators are together
-- | |- cons a to current accumulator
-- |- Don't start a new accumulator, just continue with the current
Just correct solution.
split :: Eq a => [a] -> a -> [[a]]
split xs delim = go $ dropWhile (== delim) xs
where
go [] = []
go xs = let (tok, rest) = break (== delim) xs
in tok : go (dropWhile (== delim) rest)
Data.List.Split.splitOn
(available from the split
package) is close:
> splitOn [0] [1,2,3,0,4,5,0,0,7,8,9]
[[1,2,3],[4,5],[],[7,8,9]]
> splitOn " " "Mary had a little lamb"
["Mary","had","a","little","lamb"]
Your split :: Eq a => [a] -> a -> [[a]]
would be
split lst d = filter (not.null) $ splitOn [d] lst
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.