如何在 PROLOG 中编写以下规则:如果 P 则不是 Q
我知道你可以很容易地写if P then Q谓词 like q(X) :- p(X)
,但是你怎么能否定q/1
谓词呢?我不想用其他语义定义新的谓词,比如non_q/1
.
子句“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谓词所暗示的那样)。
你听说过 Prolog 中的 cut 吗?
无论如何,我对 Prolog 标准了解不多,但在 SWI-Prolog 中,符号\+
表示否定。我知道它不必在每个 Prolog 的解释器中都起作用。
您可以使用 Prolog 的 cut 进行谓词否定。谓词定义如下:
not(Goal) :- call(Goal),!,fail.
not(Goal).
这意味着无法证明目标,而不是目标是错误的。也许这个Prolog & Cut链接会很有用。
“...if P then not Q”可以通过->
if-then 控制流谓词(例如GNU)以及\+
否定(或“不可证明”)运算符(例如GNU)来表示,如下所示:
(P -> \+ Q),
请注意,通常\+
会实现所谓的negation-as-failure;即,如果不能,子目标/表达式\+ Q
将成功。Q
请注意,Q
under的评估\+
不会影响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)
都失败的意图,但可能并不理想。X
p(X)
q(X)
您可以使用最少的逻辑来定义负头。在最小逻辑中,~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、Gopalan Nadathur、Frank Pfenning、Andre Scedrov