ここで遭遇しているのは、バックトラック時に、Prolog が前の結果を生成したときに見つけた変数バインディングを解放するという事実です。この機能は、初期の頃は多くの人を驚かせました。
最初にすべきことは、結果を取得する方法を Prolog に伝える必要性を手放し、代わりに、必要な結果を論理的に区別する方法を Prolog に伝えることに集中することです。結局のところ、これは論理プログラミングです。:) 「 と の年齢を比較するにはどうすればよいですか?」mark
と言うとき。michael
物事をつかむ方法を知ったら、自分で答えを見つけることができるという仮定の背後に本当の問題を隠しています. しかし、あなたは自分で答えを見つけたいのではなく、Prolog に見つけてもらいたいのです!
例を見てみましょう。誰の末っ子が誰であるかを調べたいとします。これは論理的に行うことができます。
?- father(Father, Child),
age(Child, YoungestAge),
\+ (father(Father, Child2),
age(Child2, Younger),
Younger < YoungestAge).
Father = john,
Child = michael,
YoungestAge = 10.
残念ながら、これは大規模なデータベースでは非効率的です。なぜなら、Prolog はage/2
特定の親のすべての子を見つけるためにすべての事実を検索する必要があるからです。おそらく、Prolog はこれらの述語をインデックス化するので、使用方法によってはそれで十分かもしれませんが、普遍的に適用できる戦略のようには見えません。しかし、このクエリの論理的な読み方に勝るものはありません。子 Child の父親があり、Child の年齢が YoungestAge であると仮定すると、YoungestAge より年齢が若い同じ父親の Child2 は存在しません。
多くの場合、すべてのソリューションが必要になります。そのために、 と の 3 つの述語がsetof/3
ありbagof/3
ますfindall/3
。それらはすべて基本的に同じ API を持ち、セマンティクスがわずかに異なります。たとえば、親のすべての子が必要な場合は、次を使用setof
してそれらを取得できます。
?- setof(Child, father(john, Child), Children).
Children = [mark, michael].
この 2 つの違いの影響を確認するには、より大きなファクト データベースが必要ですが、それは別の問題です。つまり、setof/3
一意の回答の並べ替えられたリストをbagof/3
取得しますが、すべての回答を含む並べ替えられていないリストを取得します。findall/3
は同じことを行いますが、変数の扱い方が異なります。私の経験では、setof/3
とfindall/3
は よりも多く使用される傾向がありますbagof/3
。
実行している作業で必要な場合、または効率が必要な場合は、これらのメタ述語を使用して、可能なすべてのソリューションを見つけ、必要な処理を行ってリストをたどることができます。
「クエリが複数の結果を返すことをどうすれば知ることができますか?」という質問については、答えは、基本的に、それらをすべて生成して、持っている数を確認するか ( findall(..., Answers), length(Answers, Count)
) once/1
、1 つのソリューションを確実に取得するために使用することができます。once
非決定論的な述語を決定論的にするのに最適です。効果は、節の直後にカットを置くのと基本的に同じです。例えば:
?- father(john, X).
X = mark ;
X = michael.
?- once(father(john, X)).
X = mark.
?- father(john, X), !.
X = mark.
once/1
一般に、可能であれば、明示的なカットよりも使用することをお勧めします。
これが役立つかどうか教えてください。