5

I'm making a function that removes elements that occur two or more times in a row in a list. It replaces them with one occurrence. I'm using only recursion and pattern matching (no library list functions).

Examples of how the function should work:

  • unrepeat [True,True,True,True] --> [True]
  • unrepeat [1,1,2,1,3,3,3] --> [1,2,1,3]

What I have so far:

unrepeat :: Eq a => [a] -> [a]
unrepeat [] = []
unrepeat [x] = [x]
unrepeat (x:xs) = x : [ k | k <- unrepeat(xs), k /=x]
Coding Elf
  • 53
  • 4

2 Answers2

5

I believe your implementation will remove all duplicates in the list, it looks like you want to only keep an element in the list if it is not equal to the next element.

Give this a try:

unrepeat :: Eq a => [a] -> [a]
unrepeat [] = []
unrepeat [x] = [x]
unrepeat (x1:x2:xs) = if x1 == x2 then unrepeat(x2:xs) else x1:unrepeat(x2:xs)
ktzr
  • 1,625
  • 1
  • 11
  • 25
  • 2
    You *could* write `unrepeat (x1:xs@(x2:_)) = bool id (x1:) (x1 /= x2) $ unrepeat xs`, but its readability is somewhat lacking. – chepner May 11 '18 at 18:17
0

Well, I have three, one standard recursive, one foldr recursive and one list comprehension. Each does the very same and with any list including Boolean.

First, a standard recursive

rd [] = []; rd (x:xs) = x: rd (filter (/=x) xs)

This is rather efficient. It reduces the list by the last head of the list by filtering out matches.

Reduction lends itself to folds.

rd2 ls = foldr (\x acc -> x:filter (/=x) acc) [] ls

This foldr does exactly the same as rd before it. It is more concise because the halting condition is implicit, the end of the list.

The list comprehension also halts implicitly.

rd3 ls = [d|(z,d)<- zip [0..] ls,notElem d $ take z ls]

Removing duplicates in concatenated lists is the union function. These all work without imports.

fp_mora
  • 718
  • 6
  • 11