Craig
Craig

Reputation: 405

Negation of more than two facts

Suppose you have two facts F1(x,y) and F2(x,y) and you need to define a relationship as R(X,Y) -: F1(X,Y); F1(Y,X); F2(X,Y); F2(Y,X). Now this will work although it will have multiple return values. To avoid this I used DeMorgan's Theorem (perhaps there is a better way) and got

R(X,Y) :- \+( \+F1(X,Y), \+F1(Y,X), \+F2(X,Y), \+F2(Y,X) ). 

However, this results in the error existence error(procedure, (\+)\4),R\2

So somehow it believes I am requiring R(X,Y) to have 4 arguments?

Upvotes: 1

Views: 380

Answers (1)

tas
tas

Reputation: 8140

As pointed out in the comments you need to put a space between the negation and its argument, and capital letters start variable names in Prolog. In first order logic you can't use variables for functors. That's only available in second and higher order logics (see further below for an example). But first, let's correct your code and see what happens. And for arguments sake let's add two facts for f1/2 and f2/2:

f1(a,b).
f2(x,y).

r(X,Y) :- \+ ( \+ f1(X,Y), \+ f1(Y,X), \+ f2(X,Y), \+ f2(Y,X) ).

If you query that predicate it succeeds but you don't get any variable substitutions that make the relation true:

?- r(X,Y).
true.

?- r(a,Y).
true.

?- r(a,b).
true.

?- r(a,z).
false.

The queries above show that r/2 basically works as expected, except that you only get true or false for an answer. The reason for this behaviour is the negation. Since there are facts for f1/2 and f2/2 the following queries fail:

?- \+ f1(X,Y).
false.

?- \+ f2(X,Y).
false.

And since there is no solution for those queries, you don't get substitutions for the variables. Consequently negating them again will only get you the answer true but still no substitutions:

?- \+ \+ f1(X,Y).
true.

?- \+ \+ f2(X,Y).
true.

A definition without negation on the other hand would deliver such substitutions:

r2(X,Y) :-
   f1(X,Y).
r2(X,Y) :-
   f1(Y,X).
r2(X,Y) :-
   f2(X,Y).
r2(X,Y) :-
   f2(Y,X).

?- r2(X,Y).
X = a,
Y = b ;
X = b,
Y = a ;
X = x,
Y = y ;
X = y,
Y = x.

If you, understandably, don't want to write two rules for every symmetric relation, you could opt to add facts for the functors of all the predicates you want to take into account. In this case that would only be the two relations f1/2 and f2/2:

rel(f1).
rel(f2).

Building on this you can define predicates r3/2 and rsym/3 like so:

rsym(F,X,Y) :-
   call(F,X,Y).  % calling the predicate with functor F and args X,Y
rsym(F,X,Y) :-
   call(F,Y,X).  % calling the predicate with functor F and args Y,X

r3(X,Y) :-
   rel(F),       % the relation in question has to have a functor described in rel/2
   rsym(F,X,Y).  % and is a symmetric relation

If you query this predicate you get the same results as with r2/2:

?- r3(X,Y).
X = a,
Y = b ;
X = b,
Y = a ;
X = x,
Y = y ;
X = y,
Y = x.

With only two relations f1/2 and f2/2 this doesn't make a big difference but if you have considerably more such relations, you only have to add one fact rel/2 for the functor of each of them. Note that the functors are represented with a variable (F) in r3/2 and rsym/3 just as you did in your initial attempt. But here they actually represent second order constructs.

Upvotes: 4

Related Questions