1
votes

I'm trying to write a predicate in Prolog that should work with a set of facts like these:

value(a,b)
value(d,f)
value(p,k)

Where the first value is X and second is Y. And it should write whether there are two same X values among those facts that have different Y values. In the example above the predicate should return true and in the example below the predicate should return false.

value(a,b)
value(d,f)
value(a,k)

My current predicate is this

have_different_Y_for_same_X :- relation(X, Y), not(relation(X, Z)).

All results I get no matter the values are true, so it's not working as it should.

3

3 Answers

0
votes

So I have a problem with the negation: you want it to be true if there are no such relation for an X and two different Y. The following code gives the desired result.

different_Y_for_same_X() :- 
    value(X, Y), 
    value(X, Z),
    Y @< Z.

no_different_Y_for_same_X() :- 
    \+ different_Y_for_same_X().
0
votes
diff_2nds(X) :-
    value(X, Y1), value(X, Y2),
    Y1 \= Y2.

Just write exactly what you mean. value/2 must succeed twice with different values.
This gives

?- diff_2nds(X).
X = a ;
X = a ;
false.
0
votes

1- First in checkX it collects all X's in XList.

2- In checkX1 For each X collects it's Y's in YList.

3- Then finally in checkX2, for each X checks if it's Y's are same or not using same predicate.

value(a,b).
value(d,f).
value(a,k).

checkX:-
    findall(X1,value(X1,_),XList),
    checkX1(XList,YList),
    checkX2(XList,YList).
    
checkX1([],[]).
checkX1([H|T],[YList|List]):-
    findall(Y,value(H,Y),YList),
    checkX1(T,List).

checkX2([],[]).
checkX2([H|T],[H2|T2]):-
    (   
    \+same(H2)->  
    write('X='),
    write(H),
    write(' '),
    write('Y='),
    writeln(H2),
    writeln('true'),
    checkX2(T,T2);
    write('X='),
    write(H),
    write(' '),
    write('Y='),
    writeln(H2),
    writeln('false'),
    checkX2(T,T2)).

same([]).   % You only need this one if you want the empty list to succeed
same([_]).
same([X,X|T]) :- same([X|T]).

Example:

?-checkX
X=a Y=[b, k]
true
X=d Y=[f]
false
X=a Y=[b, k]
true
1true

Here's my approach:

1- Define the facts.

2- checkX predicate finds all Y values for X using findall. It returns a list (YList=[b,k]).

3- Then check that the elements in the list are not same, using (\+) for not.

value(a,b).
value(d,f).
value(a,k).

checkX(X):-
    findall(Y,value(X,Y),YList),
    \+same(YList).
    
same([]).   % You only need this one if you want the empty list to succeed
same([_]).
same([X,X|T]) :- same([X|T]).

Example:

?-checkX(a).
1true

Now suppose I have the following facts:

value(a,k).
value(d,f).
value(a,k).

?-checkX(a).
false