Prolog がこのプログラムをどのように解決するか知りたい:
test(X, Y).
test(X, X):-!, fail.
「失敗としての否定」をグーグルで検索しましたが、混乱しています!
Prolog がこのプログラムをどのように解決するか知りたい:
test(X, Y).
test(X, X):-!, fail.
「失敗としての否定」をグーグルで検索しましたが、混乱しています!
次の例を検討してください。
father(nick, john).
X の父が Y であることを示すために、述語 Father(X,Y) を使用します。データベースにクエリを実行してみましょう。
?- father(nick,X).
X = john.
?- father(john,Y).
false.
どちらの場合も、誰が誰かの父親かを尋ねました (それぞれニック、ジョン)。最初のケースでは、prolog は答え (john) を知っていましたが、2 番目のケースでは答えを知らなかったため、答えは偽でした。つまり、ジョンには父親がいません。john の父親に関する情報を prolog に与えなかったので、prolog はunknown
. それは、何かが知られていない場合でも、それが誤りであると想定しないオープンワールドです。逆にプロローグという閉ざされた世界では、わからないことがあれば嘘だと思い込んでしまいます。
誰もが父親を持っているに違いないことを知っていることに基づいて、ジョンの父親が誰であるかを知らないと言う世界は、開かれた世界ではないことに注意してください。プロローグで簡単にモデル化できます。
data_father(nick, john).
father(X,Y):-
data_father(X,Y) -> true ; true.
一方、オープン ワールド プロローグでは、事実と反証を記述します。
father(nick, john).
not father(adam, X).
そして、これは失敗としての否定です。ただし、これはプログラムで発生することではありません。
test(X, Y).
test(X, X):-!, fail.
引数の値に関係なく、最初の句は常に成功します。実際、まさにそのため、引数に名前を付けても意味がなく、プロローグはシングルトンの警告を出します。のように句を書くことができますtest(_, _)
。
一方、2 番目の句は常に失敗します。2 つの方法で失敗する可能性があります: (1) 引数が異なる可能性があります (2) 引数が単一化可能であるため、プロローグは本体に移動してから失敗します。
プロローグが閉じた世界モデルを使用しているという理由だけで、常に失敗する句 (副作用なし (ただし、とにかく悪い習慣と見なされます)) を持つ意味はありません。逆に、これらの余分な呼び出しにより、プログラムの実行が遅くなり、より多くのメモリが使用されます。
!/0
カット ( ) に到達すると選択ポイントがなくなるため、ここではカット ( ) は何もしないことにも注意してください。ただし、次の例を検討してください。
test(X, Y).
test(X, X):-!, fail.
test(X, 42).
?- test(1,42).
true ;
true.
?- test(42,42).
true ;
false.
どちらの場合も、プロローグは各句に 1 つずつ、合計 3 つの選択ポイントを作成します。最初のケースでは、本体がないため、Prolog は最初の節の先頭に一致し、成功します。次に、2 番目の節の頭部の突き合わせに失敗し、本体は「実行」されません。最後に、3 番目の句の先頭に一致し、本文がないため成功します。
ただし、2 番目のケースでは、Prolog は最初の節の頭部の一致に成功し、本体がないため成功します。次に、2 番目の句の先頭の一致に成功します。カットは他のすべての選択ポイントを削除し、 が原因で失敗しfail
ます。したがって、prolog は 3 番目の句を試行しません。
あなたがそれについて言及したので、失敗としての否定についてのいくつかの言葉。失敗としての否定は、閉じた世界の仮定に基づいています。すでに持っている事実から導き出せないものはすべて間違っていると仮定しているため、何かを証明できなければ、その反対が真実であると見なされることを意味します。たとえば、次のように考えてください。
father(nick, john).
fatherless(X) :- \+ father(X, _).
と
?- fatherless(nick).
false.
?- fatherless(john).
true.
逆に、オープン ワールドでは、次のコードでプロローグします。
father(nick, john).
not father(adam, X).
fatherless(X) :- \+ father(X, _).
fatherless/1
でのみ成功しadam
、ニックで失敗し、unknown
それ以外の場合は戻ります
最初の節test(X, Y).
は、引数のパターンが何であれ、test/2 が無条件に真であることを示しています。
2 番目の節test(X, X):-!, fail.
は、test/2 が単一化可能な1 番目と 2 番目の引数で呼び出された場合、それ以上の選択肢はなく、失敗することを示しています (常に失敗することに注意してください。これは、引数スキーマが最初の引数 \= 2 番目の引数であるインスタンス化パターンを暗黙的に除外しているためです) )。
' Closed World Assumption ' の下の論理否定と同じ場合の操作効果。