非終了は、Prolog で理解するのが少し難しいことがよくあります。クエリを例にとりますpn(X)
。明らかに、次のものが必要です。
W = [hans] ;
W = [den, mann] ;
W = [den, fernrohr] ;
W = [dem, mann] ;
W = [dem, fernrohr].
解決策として([den, fernrohr]
ドイツ人でなくても)。しかし、Prolog は 1 つだけを見つけてからループします。ある意味で、あなたは自分自身を幸せだと考えることができます。なぜなら、その問題を早い段階で発見したからです。しかし、ループの前に多くの答えがある状況を想像してください。だから、あなたはすべてがうまくいっているという印象を持っていますが、そうではありません.
これらの問題をもう少し早く見つけるには、pn(X), false
代わりに質問してください。このクエリは真になることはありませんが、 とまったく同じ方法で終了しますが、pn(X)
これらの刺激的なソリューションがすべて生成されるわけではありません。
プログラムに挿入することで、さらに一歩進めることができfalse
ます。結果として得られるプログラムは、失敗スライスと呼ばれます。純粋で単調なプログラムを使用すると、次のことが成り立ちます。
障害スライスが (特定のクエリで)終了しない場合、元のプログラムはそのクエリで終了しません。
通常、障害スライスははるかに短いため、読み取りと理解が速くなります。の場合np(X)
?- np(X), false .
np(W) :-
( append(W1,W2,W), false , pn(W1), ph(W2)
; false , append(W1,W2,W), det(W1), n(W2)
)。
pn/1
そのため、 、ph/1
、det/1
、またはn/1
for ループの検索に時間を無駄にする必要はもうありません。上記の障害スライスだけでは、すでに非終了が発生しています。したがって、これが修正されない限り、残りのプログラムを調べても意味がありません。
簡単な修正はappend/3
、最後に置くことです。それはnp/1
. ただし、固定長のリストを持つ再帰的な非終端記号では機能しません。
Prolog が誕生する前は、人々はまさにそのようなエンコーディングを検討していました。彼らはこの不一致に戸惑いました: 文法と述語論理の両方が宣言的形式主義です。しかし、多くの文法は非常に効率的に解析できますが、文が文法によって記述されていることを証明するには、膨大な検索スペースが必要になるようです。ここでロジックを使用するこの効果的な方法はどこにありますか?
その答えは、単純な文法を手書きのパーサーと同じくらい効率的に解析できる特定のエンコーディングであり、それが Prolog を生み出しました。今日まで、このエンコーディングは Prolog で定句文法を実装するために使用されています。これがどのように行われるかは、@WouterBeeksの回答を参照してください。