Reputation: 1673
i try to concatenate two lists such that the elements in the resulting list occurs only once. i didnt want to use a predefined function because then it would be too easy. so because of i am learning haskell i write the following code:
import Data.List
add :: [Int] -> [Int] -> [Int]
add xs ys = zs ++ ws
where
zs = if elem x (x:xs) == True then x:(elem x xs)
else elem x xs
ws = if elem y (y:ys) == True then y:(elem y ys)
else elem y ys
i only use the predefined function elem which tells me if an element occurs in the list. my idea was to take one list first and use "elem" to find out if the first element x of the list xs exists in the list more than once. If that so, then i take that x and with ":"-operator and (elem x xs) i build up a new list until all elements are checked. The same thing i do with the second list. If is done, then i use "++" - operator to concatenate the duplicate-free lists with zs ++ ws. So when I compile it, then ghci tells me that x and y are not in scope. Where i my mistake ?
Upvotes: 1
Views: 8572
Reputation: 8136
I think Chris's solution is the way to go. But for the sake of teaching, I will discuss some of the problems in your approach. First of all, in order to reference x
and y
in your function add
, they must be defined somewhere. I suspect what you intended was:
add (x:xs) (y:ys) = ...
Now you can use x
, xs
, y
and ys
in your function definition. Now any time you're tempted to write something like:
if condition == True then...
know that it's simpler and clearer to just write
if condition then...
So I think you were intending to write something kind of like this:
add (x:xs) (y:ys) = zs ++ ws
where
zs = if elem x xs then xs
else x:xs
ws = if elem y ys then ys
else y:ys
except that you also wanted to do some sort of recursion to make sure that none of the elements in xs
or ys
is repeated. However, recursing down two lists would be very awkward and difficult to do. That's why Chris's answer is better, and the more Haskell-y way to approach it.
Note also that instead of
elem x xs
it can be more readable to write
x `elem` xs
Upvotes: 6
Reputation: 47402
You haven't given examples of the expected input/output of this function, so I'll work with the definition that you gave -
"Concatenate two lists such that the elements in the resulting list occur only once."
It seems like there's a straightforward way to do this -
So let's assume you have a function unique :: [Int] -> [Int]
that removes duplicates from a list (while keeping the elements in order). Then what you want is as simple as
add :: [Int] -> [Int] -> [Int]
add xs ys = unique (xs ++ ys)
so you've reduced the problem to the simpler one of writing the unique
function. Can you do that?
Upvotes: 8