The main problem of predicates like integer/1 , atom/1 , etc. lies in the fact that they are not monotonous .
Take for example ?- integer(5). that succeeds. But a more general goal ?- integer(X). fails !
For declarative debugging and automatically generated explanations, we expect that if a goal is successful, every generalization of that goal should not fail.
"Correct" (i.e. if you want nice monotone predicates that make declarative sense), it would be for integer/1 to create an instance creation error, for example ?- integer(X). on the grounds that she does not have enough information to answer the question at this time. Instead of integer/1 you should use must_be/2 from library(error) to get this sound behavior:
?- must_be(integer, X). ERROR: Arguments are not sufficiently instantiated
must_be/2 behaves monotonously, which is usually a good property.
Extending the comment: the problem is that (at least if the results above are correct), your predicate is no longer a true relation, since goals are now not commutative ?- X = 0, X = Y, addUnique([X,Y,3],3). succeeds, but simply exchanges the order of goals does not give the same result, because ?- X = Y, addUnique([X,Y,3], 3), X = 0. fails.
Such phenomena are a common consequence of the use of meta-logical predicates. A declarative solution to such problems is limitations , see, for example, dif/2 . They are monotonous, commutative, and generally much easier to understand.