Hi,
I'll try to explain the meaning of different parts of the comprehension::
unique xs = [x | (x,y) <- zip xs [0..], x `notElem` (take y xs)]
this part means: consider the couples (x,y) that are output of zip xs [0..]
for example if xs = [10,20,10,30,30], you are taking [(10,0),(20,1),(10,2),(30,3),(30,4)]
unique xs = [x | (x,y) <- zip xs [0..], x `notElem` (take y xs)]
this part means: among the things you considered before (i.e. all the couples obtained before), consider only those that satisfy the property that the first element of (x,y) is not an alement of a certain list (take y xs, i.e. the first y elements of xs).
So in the example above:
is 10 an element of (take 0 xs)=[ ] ? No ----> we consider (10,0)
is 20 an element of (take 1 xs)=[10]? No ----> we consider (20,1)
is 10 an element of (take 2 xs)=[10,20]? Yes ----> we DON'T consider (10,2)
is 30 an element of (take 3 xs)=[10,20,10]? No ----> we consider (30,3)
is 30 an element of (take 4 xs)=[10,20,10,30]? Yes ----> we DON'T consider (30,4)
So we are considering only [(10,0),(20,1),(30,3)]
So as you said this is a refinement of the elements generated by the first generator. A refinement means that some of the elements
generated before are (possibly) discarded, so you don't obtain a [Bool], but something of the same type of what was generated before, i.e. another [(Eq,Int)] possibly shorter than the previous one.
Finally
unique xs = [x | (x,y) <- zip xs [0..], x `notElem` (take y xs)]
this part says that, of each couple produced and refined before, you take the first element (that was called x).
So in the example you get [10,20,30]
Hope this is clear,
Ut