13

如何在 PROLOG 中编写以下规则:如果 P 则不是 Q

我知道你可以很容易地写if P then Q谓词 like q(X) :- p(X),但是你怎么能否定q/1谓词呢?我不想用其他语义定义新的谓词,比如non_q/1.

4

4 回答 4

15

子句“if P then not Q”在逻辑上等价于否定子句“not P OR not Q”。因此,它是一个没有肯定文字的Horn 子句,并且作为 SLD 定理证明和 Horn 子句对应的应用,可以在 Prolog 编程中表示为目标子句或“查询”:

?- P, Q.

让我们马上回到这个想法。

但是目标子句可能不是您想到的那种表示形式。构成Prolog“知识库”的事实和规则是明确的条款,即Horn 条款,每个条款都只有一个肯定的文字。“如果 P 那么不是 Q”没有肯定的文字,所以在这个意义上它不能被表示(作为一个明确的子句)。

上面显示的目标子句“询问”P 和 Q 是否都可以被证明。Prolog 提供了“否定即失败”的概念,因此“询问”“非 P 或非 Q”是否成立的更自然的方法是:

?- not((P,Q)).

然后,如果 P 或 Q 失败,我们将获得成功,如果两者都成功,则失败。

但是,如果您的目的是在知识库中断言否定,Prolog 自然不会支持这一点。根据您的应用程序,可能有一种合理的方法来解决 Prolog 语法并完成所需的工作(总是有一种不合理的方法来做到这一点,正如您使用non_q谓词所暗示的那样)。

于 2011-06-13T18:54:15.667 回答
8

你听说过 Prolog 中的 cut 吗?

无论如何,我对 Prolog 标准了解不多,但在 SWI-Prolog 中,符号\+表示否定。我知道它不必在每个 Prolog 的解释器中都起作用。

您可以使用 Prolog 的 cut 进行谓词否定。谓词定义如下:

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

这意味着无法证明目标,而不是目标是错误的。也许这个Prolog & Cut链接会很有用。

于 2011-06-13T15:44:50.850 回答
3

“...if P then not Q”可以通过->if-then 控制流谓词(例如GNU)以及\+否定(或“不可证明”)运算符(例如GNU)来表示,如下所示:

(P -> \+ Q),

请注意,通常\+会实现所谓的negation-as-failure;即,如果不能,子目标/表达式\+ Q将成功。Q请注意,Qunder的评估\+不会影响Q执行时表达式中存在的任何变量的绑定。

例如,考虑:

foo(a).
bar(b).

鉴于这些事实,以下观点成立:

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.

正如您所描述的那样,实现类似于\+ q(X) :- p(X)您可能想要的东西(就“规则”而言)并不简单,但是潜在的黑客攻击是:

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

该定义将仅反映如果在 的任何其他子句之前断言所有成功的地方q(X)都失败的意图,但可能并不理想。Xp(X)q(X)

于 2011-06-14T05:10:24.550 回答
1

您可以使用最少的逻辑来定义负头。在最小逻辑中,~A 可以被视为 A -> ff。因此以下

P -> ~Q

可以看成:

P -> (Q -> ff).

现在,如果我们采用以下恒等式 (A -> (B -> C)) = (A & B -> C),我们看到上述等价于:

P & Q -> ff.

现在有一个问题,我们如何提出否定查询?有一种方法可以利用最小逻辑,它不同于否定作为失败。这个想法是表单的查询:

G |- A -> B

答案是暂时将A加到prolog程序G中,然后尝试求解B,即执行以下操作:

G, A |- B

现在让我们转向 Prolog 符号,我们将通过执行(最小逻辑)Prolog 程序来证明 p,并且 p -> ~q 暗示 ~q。序言程序是:

p.
ff :- p, q.

查询是:

?- q -: ff.

我们首先需要定义新的连接词 (-:)/2。一个快速的解决方案如下:

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

在这里,您可以在 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 .

此致

参考:统一证明作为逻辑编程的基础 (1989),作者 Dale Miller、Gop​​alan Nadathur、Frank Pfenning、Andre Scedrov

于 2011-06-14T14:04:57.180 回答