Prolog implying a negative predicate

这一生的挚爱 提交于 2019-12-04 08:07:53

问题


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.


回答1:


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).




回答2:


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:


"...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.




回答4:


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



来源:https://stackoverflow.com/questions/6332539/prolog-implying-a-negative-predicate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!