4
votes

I want to write a Prolog predicate that returns true when two people have the same hobby, without using negation. I have the following database:

likes(john,movies). 
likes(john,tennis). 
likes(john,games). 
likes(karl,music). 
likes(karl,running). 
likes(peter,swimming).
likes(peter,movies). 
likes(jacob,art). 
likes(jacob,studying). 
likes(jacob,sleeping). 
likes(mary,running). 
likes(mary,sleeping). 
likes(sam,art). 
likes(sam,movies).

I came up with the following predicate:

same_hobby(X,Y) :-
   likes(X,Z),
   likes(Y,Z).

However, this predicate is also true when X equals Y and I do not want this to be the case. Can anyone help me find a solution? A small explanation would also be greatly appreciated.

2
Simply use dif/2: This predicate is true iff its arguments are different. So: same_hobby(X, Y) :- dif(X, Y), likes(X, Hobby), likes(Y, Hobby).mat
Do keep in mind that prolog predicates don't return anything. They just succeed or fail.Enigmativity
@Enigmativity or sometimes they go off into never-never land... :plurker
@lurker - Very true. If only we could write a program that would prove if they would finish or not. ;-)Enigmativity

2 Answers

2
votes

You can simply use the predicate dif/2 , that is, dif(Term1, Term2) that means that Term1 have to differ from Term2, otherwise it will fail. Your rule will become:

same_hobby(X,Y) :-
            likes(X,Z),
            likes(Y,Z),
            dif(X,Y).

Cause dif/2 is a completely pure predicate, you can also write this as

same_hobby(X,Y) :-
            dif(X,Y),
            likes(X,Z),
            likes(Y,Z).

That means that, if X differs from Y then reduce the goal likes(X,Z), likes(Y,Z), fail otherwise.

2
votes

You can use the predicate dif/2 to state that X and Y must not be equal:

same_hobby(X, Y) :-
    likes(X, Z),
    likes(Y, Z),
    dif(X, Y).

This makes it so the interpreter recognizes that X and Y need to be two different entities in order for the same_hobby/2 predicate to be true.