(SWI)Prolog: Order of sub-goals
H\==Elem
is testing for syntactic inequality at the point in time when the goal is executed. But later unification might make variables identical:
?- H\==Elem, H = Elem.
H = Elem.
?- H\==Elem, H = Elem, H\==Elem.
false.
So here we test if they are (syntactically) different, and then they are unified nevertheless and thus are no longer different. It is thus just a temporary test.
The goal member(Elem, T)
on the other hand is true if that Elem
is actually an element of T
. Consider:
?- member(Elem, [X]).
Elem = X.
Which can be read as
(When) does it hold that
Elem
is an element of the list[X]
?
and the answer is
It holds under certain circumstances, namely when
Elem = X
.
If you now mix those different kinds of goals in your programs you get odd results that can only explained by inspecting your program in detail.
As a beginner, it is best to stick to the pure parts of Prolog only. In your case:
use
dif/2
in place of\==
do not use cuts - in your case it limits the number of answers to two. As in
unique_element(X, [a,b,c])
do not use
not/1
nor(\+)/1
. It produces even more incorrectness. Considerunique_element(a,[a,X]),X=b.
which incorrectly fails whileX=b,unique_element(a,[a,X])
correctly succeeds.
Here is a directly purified version of your program. There is still room for improvement!
non_member(_X, []).
non_member(X, [E|Es]) :-
dif(X, E),
non_member(X, Es).
unique_element(Elem, [Elem|T]) :-
non_member(Elem, T).
unique_element(Elem, [H|T]) :-
dif(H,Elem),
% member(Elem, T), % makes unique_element(a,[b,a,a|Xs]) loop
unique_element(Elem, T).
?- unique_element(a,[a,X]).
dif(X, a)
; false. % superfluous
?- unique_element(X,[E1,E2,E3]).
X = E1,
dif(E1, E3),
dif(E1, E2)
; X = E2,
dif(E2, E3),
dif(E1, E2)
; X = E3,
dif(E2, E3),
dif(E1, E3)
; false.
Note how the last query reads?
When is
X
a unique element of (any) list[E1,E2,E3]
?
The answer is threefold. Considering one element after the other:
X
isE1
but only if it is different toE2
andE3
etc.
TL;DR: Read the documentation and figure out why:
?- X = a, X \== a.
false.
?- X \== a, X = a.
X = a.
I wonder why you stop so close from figuring it out yourself ;-)
There are too many ways to compare things in Prolog. At the very least, you have unification, which sometimes can compare, and sometimes does more; than you have equvalence, and its negation, the one you are using. So what does it do:
?- a \== b. % two different ground terms
true.
?- a \== a. % the same ground term
false.
Now it gets interesting:
?- X \== a. % a free variable and a ground term
true.
?- X \== X. % the same free variable
false.
?- X \== Y. % two different free variables
true.
I would suggest that you do the following: figure out how member/2
does its thing (does it use unification? equivalence? something else?) then replace whatever member/2
is using in all the examples above and see if the results are any different.
And since you are trying to make sure that things are different, try out what dif/2
does. As in:
?- dif(a, b).
or
?- dif(X, X).
or
?- dif(X, a).
and so on.
See also this question and answers: I think the answers are relevant to your question.
Hope that helps.
Can you not define unique_element like tcount Prolog - count repetitions in list
unique_element(X, List):- tcount(=(X),List,1).