PROLOGで次のルールを書くにはどうすればよいですか:Pの場合はQではありません
P、Qのように述語を書くと簡単に書けると思いますが、どうすれば述語q(X) :- p(X)
を否定できますq/1
か?のような他のセマンティクスで新しい述語を定義したくありませんnon_q/1
。
「ifPthennot Q」という節は、否定的な節「not PORnotQ」と論理的に同等です。そのようなものとして、それは正のリテラルのないホーン節であり、SLD定理証明とホーン節の対応のアプリケーションとして、Prologプログラミングでゴール節または「クエリ」として表すことができます。
?- P, Q.
すぐにこのアイデアに戻りましょう。
しかし、目標節はおそらくあなたが考えているような表現ではありません。Prologの「知識ベース」を構成する事実と規則は明確な節です。つまり、ホーン節はそれぞれ1つの正のリテラルを持っています。「IfPthennot Q」には正のリテラルがないため、この意味で(明確な句として)表すことはできません。
上記の目標節は、PとQの両方を証明できるかどうかを「尋ねます」。Prologは「失敗としての否定」の概念を提供するので、「PではないかQではない」が成り立つかどうかを「尋ねる」より自然な方法は次のようになります。
?- not((P,Q)).
次に、PまたはQのいずれかが失敗した場合は成功し、両方が成功した場合は失敗します。
しかし、あなたの目的が知識ベースで否定を主張することである場合、Prologは当然これをサポートしません。アプリケーションによっては、Prolog構文を回避し、必要なことを実行するための合理的な方法がある場合があります(non_q述語の場合と同様に、それを行うには常に不合理な方法があります)。
Prologのカットについて聞いたことがありますか?
とにかく私はProlog標準についてあまり知りませんが、SWI-Prologでは記号\+
は否定を意味します。私はそれがすべてのPrologのインタプリタで機能する必要はないことを知っています。
Prologのカットを使用して述語の否定を行うことができます。述語は次のように定義されます。
not(Goal) :- call(Goal),!,fail.
not(Goal).
それは、目標が間違っているのではなく、目標を証明できないことを意味します。たぶん、このProlog&Cutリンクが役立つでしょう。
「...ifPthen not Q」は、次のように、否定(または「証明できない」)演算子(GNUなど)とともに、 ->
if-then制御フロー述語(GNUなど)を介して表すことができます。\+
(P -> \+ Q),
通常、失敗による否定として\+
知られているものを実装することに注意してください。つまり、サブゴール/式は成功しない場合は成功します。underの評価は、実行時に式に存在する変数のバインディングに影響を与えないことに注意してください。\+ Q
Q
Q
\+
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).
ここで、次のID(A->(B-> C))=(A&B-> C)をとると、上記は次のようになります。
P & Q -> ff.
ここで1つの問題があります。どうすれば否定的な質問をすることができますか?失敗による否定とは異なる最小限のロジックを利用する方法が1つあります。アイデアは、次の形式のクエリです。
G |- A -> B
一時的にプロローグプログラムGにAを追加し、次にBを解こうとすることによって答えられます。つまり、次のようにします。
G, A |- B
ここで、Prolog表記に目を向けましょう。pを示します。p->〜qは、(最小論理)Prologプログラムを実行することによって〜qを意味します。プロローグプログラムは次のとおりです。
p.
ff :- p, q.
そして、クエリは次のとおりです。
?- q -: ff.
まず、新しい接続(-:)/2を定義する必要があります。簡単な解決策は次のとおりです。
(A -: B) :- (assert(A); retract(A), fail), B, (retract(A); assert(A), fail).
ここに、SWIPrologでのこの最小限の論理否定の実現が示されています。
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