13
votes

How can I write the following rule in PROLOG: if P then not Q

I understand that you can easily write if P then Q the predicates like q(X) :- p(X), but how can you negate the q/1 predicate? I don't want to define new predicates with other semantics like non_q/1.

4
i think that the way of the implementation depends on the way you are going to use it. What are you trying to do? After all, Prolog is a subset of First Class Logic (Horn Clauses in pure Prolog)Thanos Tintinidis

4 Answers

15
votes

The clause "if P then not Q" is logically equivalent to the negative clause "not P OR not Q". As such it is a Horn clause without a positive literal, and as an application of the correspondence of SLD theorem proving and Horn clauses, can be represented in Prolog programming as a goal clause or "query":

?- P, Q.

Let's come back to this idea in a minute.

But the goal clause is perhaps not the sort of representation you have in mind. The facts and rules that constitute a Prolog "knowledgebase" are definite clauses, i.e. Horn clauses each with exactly one positive literal. "If P then not Q" has no positive literal, so in this sense it cannot be represented (as a definite clause).

The goal clause shown above "asks" if P and Q can both be proven. Prolog provides a notion of "negation as failure", so a more natural way to "ask" whether "not P OR not Q" holds would be:

?- not((P,Q)).

Then we would get success if either P or Q fails, and failure if both succeed.

However if your purpose is to assert the negation something in the knowledgebase, Prolog doesn't naturally support this. Depending on your application, there may be a reasonable way to work around the Prolog syntax and accomplish what is needed (there's always an unreasonable way to do it, as you've hinted as with a non_q predicate).

8
votes

Have you ever heard about cut in Prolog?

Anyway I don't know much about Prolog standard, but in SWI-Prolog the symbol \+ means negation. I know it don't have to work in every Prolog's interpreter.

You can make the predicate negation with Prolog's cut. The predicate is defined like:

not(Goal) :- call(Goal),!,fail.
not(Goal). 

It means that Goal can't be proven, not the Goal is false. Maybe this Prolog & Cut link will be useful.

3
votes

"...if P then not Q" can be represented via the -> if-then control-flow predicate (e.g., GNU) , along with the \+ negation (or 'not-provable') operator (e.g., GNU), as follows:

(P -> \+ Q),

Note that, typically, \+ will implement what is known as negation-as-failure; i.e., the subgoal/expression \+ Q will succeed iff Q cannot. Note that the evaluation of Q under \+ will not affect the bindings of any variables present in the expression Q at execution.

For example, consider:

foo(a).
bar(b).

Given these facts, the following hold:

foo(a) -> \+ bar(a). % succeeds, as bar(a) is not provable.
foo(a) -> \+ bar(b). % fails, as bar(b) is provable.
foo(a) -> \+ bar(X). % fails, as bar(X) is provable; note that X remains unbound.
foo(X) -> \+ bar(X). % succeeds, as bar(X) where X unified to 'a' isn't provable.

Implementing something akin to \+ q(X) :- p(X) as you might want (in terms of a 'rule') isn't straightforward, as you describe, however a potential hack is:

q(X) :- p(X), !, fail.

This definition will only reflect the intention that q(X) is to fail for all X where p(X) succeeds iff it is asserted before any other clauses of q(X), but may not be ideal.

1
votes

You can use minimal logic to define a negative head. In minimal logic ~A can be viewed as A -> ff. Thus the following

P -> ~Q

Can be viewed as:

P -> (Q -> ff).

Now if we take the following identity (A -> (B -> C)) = (A & B -> C), we see that the above is equivalent to:

P & Q -> ff.

There is now one problem, how can we ask negative queries? There is one way to make use of minimal logic which is different from negation as failure. The idea is that a query of the form:

G |- A -> B

is answered by temporarily adding A to the prolog program G, and then trying to solve B, i.e. doing the following:

G, A |- B

Now lets turn to Prolog notation, we will show that p, and p -> ~q implies ~q by executing a (minimal logic) Prolog program. The prolog program is:

p.
ff :- p, q.

And the query is:

?- q -: ff.

We first need to define the new connective (-:)/2. A quick solution is as follows:

(A -: B) :- (assert(A); retract(A), fail), B, (retract(A); assert(A), fail).

Here you see a realisation of this minimal logic negation in SWI Prolog:

Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 5.10.4)
Copyright (c) 1990-2011 University of Amsterdam, VU Amsterdam

1 ?- [user].
:- op(1200,xfy,-:).
|: (A -: B) :- (assertz(A); retract(A), fail), B, (retract(A); assertz(A), fail).
|: p.
|: ff :- p, q.
|:
% user://1 compiled 0.02 sec, 1,832 bytes
true.

2 ?- q -: ff.
true .

Best Regards

Reference: Uniform Proofs as a Foundation for Logic Programming (1989) by Dale Miller, Gopalan Nadathur, Frank Pfenning, Andre Scedrov