Masood Delfarah
Masood Delfarah

Reputation: 697

What is the logical 'not' in Prolog?

The problem that I face, is a bit trivial. I want to use logical not in Prolog, but it seems that not/1 is not the thing that I want:

course(ai).
course(pl).
course(os).

have(X,Y) :- course(X),course(Y),not(X = Y).

I query:

have(X,Y), write(X-Y), nl , fail.

And I do not get the result I want :(

Upvotes: 45

Views: 133639

Answers (5)

false
false

Reputation: 10102

In place of not(X = Y) you need to write \+ X = Y or X \= Y. But consider to use dif(X,Y) instead. dif/2 is present in B, SWI, YAP, SICStus. To see the difference:

?- X = b, dif(a, X).
   X = b.
?- X = b, \+ a = X.
   X = b.

So up to now everything seems to be fine. But what, if we simply exchange the order of the two goals?

?- \+ a = X, X = b.
   false. 
?- dif(a, X), X = b.
   X = b.

(\+)/1 now gives us a different result, because there is an answer for a = X, the goal \+ a = X will fail.

(\+)/1 is thus not negation, but means not provable at this point in time.

A safe approximation of dif/2 is possible in ISO Prolog, too.

Upvotes: 42

Niloct
Niloct

Reputation: 9995

Reading Samuel Kamin's book on chapter 8, prolog, I found this solution that also fits here and explains how to use the cut:

The cut is a way of giving the programmer additional control over the computation by allowing him to indicate places where backtracking is impermissible. Specifically, the cut is written as an exclamation mark (!) occurring as a goal in the right-hand side of a clause such as:

G :- H, !, R.

Suppose this clause is chosen to satisfy a goal g with which G unifies. An attempt is made to satisfy H. If successful, R is proven. If the proof of R succeeds, then g is proven; in this case, the cut has no part to play. If, however, the proof of R fails, rather than backtrack and try to re-prove H, the presence of the cut causes the goal g to fail immediately; this occurs even if there are further clauses that might apply to g. An example is the definition of not-equals:

equals(X, X).
not-equals(X, Y) :- equals(X, Y), !, fail.
not-equals(X, Y).

not-equals(X, Y) should succeed if X is not equal to Y, and fail if it is; X and Y should be bound to ground expressions (i.e. have no free variables) when attempting to satisfy this goal.

Upvotes: 6

Kaitain
Kaitain

Reputation: 960

As an adjunct to the answer by user "false" above, i.e.

"In place of not(X = Y) you need to write \+ X = Y,"

This might give the impression that:

a. "not" and "\+" are different things

b. The \+ will work whereas the not will, err, not.

My understanding is that "not" and "\+" are equivalent, but that \+ is preferred in modern Prolog programs, because it conveys a sense that is more intuitive. Specifically, whereas "not" might suggest "is not true" to the unwary coder, "\+" suggests "is not provable" which is much closer to the truth of what that operation is really saying. In Prolog, the "not" is an example of "negation as failure", but it is felt that \+ will make it clearer to the programmer just what precisely is being asserted in any given rule. So you CAN use "not" (most PL implementations keep it for backwards-compatibility) but to be an idiomatic modern PL programmer, you probably should prefer to use \+.

Upvotes: 6

Igbanam
Igbanam

Reputation: 6082

Like you said, OP, this is trivial.

Try

course(ai).
course(pl).
course(os).

have(X,Y) :- course(X), course(Y), X \== Y).

That should fix your predicate.

Looking one step ahead though, mathematically phrasing, you are probably looking for the solution to (n C 2) as opposed to (n P 2) which your predicate currently provides—combination instead of permutation, choice of selection as opposed to arrangements of choices of selection. This is what I think.

If this is what you want, I would suggest you try

course(ai).
course(pl).
course(os).

have(X,Y) :- course(X), course(Y), X @< Y).

Which would prevent duplicate reversed results.

@< means atomically less than. < is for integers, @< is for atoms.

Upvotes: 2

Fred Foo
Fred Foo

Reputation: 363487

In both SWI-Prolog and GNU Prolog, the following should work:

have(X, Y) :- course(X), course(Y), X \= Y.

In SWI-Prolog, you can also use dif/2, which can be more convenient since you can use it earlier in the predicate:

have(X, Y) :- dif(X, Y), course(X), course(Y).

Upvotes: 15

Related Questions