I'm guessing that you're a student, and this is a homework problem, so I'll give you part of the answer and let you finish it. In order to write remdups, it would be useful to have a function that tells us if a list contains an element. We can do that using recursion. When using recursion, start by asking yourself what the "base case", or simplest possible case is. Well, when the list is empty, then obviously the answer is False (no matter what the character is). So now, what if the list isn't empty? We can check if the first character in the list is a match. If it is, then we know that the answer is True. Otherwise, we need to check the rest of the list -- which we do by calling the function again.
elem _ [] = False
elem x (y:ys) = if x==y
then True
else elem x ys
The underscore (_) simply means "I'm not going to use this variable, so I won't even bother to give it a name." That can be written more succinctly as:
elem _ [] = False
elem x (y:ys) = x==y || elem x ys
Writing remdups is a little tricky, but I suspect your teacher gave you some hints. One way to approach it is to imagine we're partway through processing the list. We have part of the list that hasn't been processed yet, and part of the list that has been processed (and doesn't contain any duplicates). Suppose we had a function called remdupHelper, which takes those two arguments, called remaining and finished. It would look at the first character in remaining, and return a different result depending on whether or not that character is in finished. (That result could call remdupHelper recursively). Can you write remdupHelper?
remdupHelper = ???
Once you have remdupHelper, you're ready to write remdups. It just invokes remdupHelper in the initial condition, where none of the list has been processed yet:
remdups l = remdupHelper l [] -- '