I’m trying to write my implementation of remdps, function, which removes nearest duplicates in a list. For example: "aaabbbsscaa" should became "absca". I have to use foldl. Here is my attempt:
helper :: Eq a => [a] -> a -> [a]
helper [] ele = [ele]
helper newlist ele = if tail newlist /= ele then newlist:ele
else newlist
remdps :: Eq a => [a] -> [a]
remdps list = foldl helper [] list
main = putStrLn (show (remdps "aabssscdddeaffff"))
And the error:
4.hs:4:41:
Could not deduce (a ~ [a])
from the context (Eq a)
bound by the type signature for helper :: Eq a => [a] -> a -> [a]
at 4.hs:2:11-33
`a' is a rigid type variable bound by
the type signature for helper :: Eq a => [a] -> a -> [a]
at 4.hs:2:11
In the second argument of `(/=)', namely `ele'
In the expression: tail newlist /= ele
In the expression:
if tail newlist /= ele then newlist : ele else newlist
4.hs:4:50:
Could not deduce (a ~ [a])
from the context (Eq a)
bound by the type signature for helper :: Eq a => [a] -> a -> [a]
at 4.hs:2:11-33
`a' is a rigid type variable bound by
the type signature for helper :: Eq a => [a] -> a -> [a]
at 4.hs:2:11
In the first argument of `(:)', namely `newlist'
In the expression: newlist : ele
In the expression:
if tail newlist /= ele then newlist : ele else newlist
4.hs:4:58:
Could not deduce (a ~ [a])
from the context (Eq a)
bound by the type signature for helper :: Eq a => [a] -> a -> [a]
at 4.hs:2:11-33
`a' is a rigid type variable bound by
the type signature for helper :: Eq a => [a] -> a -> [a]
at 4.hs:2:11
In the second argument of `(:)', namely `ele'
In the expression: newlist : ele
In the expression:
if tail newlist /= ele then newlist : ele else newlist
fish: Unknown command './4'
ghc 4.hs; and ./4
The question is always the same:). What’s wrong?
//edit
OK, I have a working code. It uses reverse and ++, so it’s very ugly:).
helper :: Eq a => [a] -> a -> [a]
helper [] ele = [ele]
helper newlist ele = if head (reverse newlist) /= ele then newlist ++ [ele]
else newlist
remdps :: Eq a => [a] -> [a]
remdps list = foldl helper [] list
main = putStrLn (show (remdps "aabssscdddeaffff"))
What you’re probably trying to do is this:
The changes:
:works only in one way: on the left is the head of the list (typea), on the right the tail (type[a]). It’s sometimes also called “cons”. What you want to do is called “snoc”: on its right is the last element of the list (typea), and on the left the initial part (type[a]).“snoc” doesn’t exist in the Prelude, so instead, you just write it in a different way:
newlist ++ [ele]. (Compare this tox : xs == [x] ++ xs.)tail newlist == elebecomeslast newlist == ele.tailgets the list without its head, but you want to compare the last element ofnewlist. For that purpose, you havelast. (By the way, to get the initial part of a list, you can useinit.)Note that you’ve also swapped the branches of your if-statement, leaving you with-edit- I see that you’ve updated that now 😉aaaas the answer.Also note that this is a very slow approach. Every “snoc” and
lastwill take longer as the answer ofremdpsgrows, because Prelude lists are much better at “cons” andhead. Try rewriting the function so that it uses “cons” instead. Hint: you’ll needreverseat some point.Furthermore, this function will not work when used with infinite lists, because of the way
foldlworks. It might be an interesting exercise to rewrite this function to usefoldrinstead.