3

私はこのコードを持っています

s(W) :- append(W1,W2,W), np(W1), vp(W2).

vp(W) :- append(W1,W2,W), v(W1), np(W2).

np(W) :-
   (  append(W1,W2,W), pn(W1), ph(W2)
   ;  append(W1,W2,W), det(W1), n(W2)
   ).

pn([hans]).

ph([]).

v([beobachtet]).

n([mann]).
n([fernrohr]).

p([mit]).

det([den]).
det([dem]).

私が何かをキャストしnp(X). vp(X).たりpp(X)、可能な解析を1つ取得したりして、スタックエラーが発生した場合。私がキャストするとき、私s(X).は解析さえしません。無限ループが実行されているためだとはわかっていますが、どの時点でループされるかはわかりません。すべての変数に同じ名前を使用しているために発生する可能性があると考えましたが、それらを個別の名前に変更しても何も変わりませんでした。

誰でもヒントを得ましたか?

前もって感謝します!

4

2 に答える 2

4

非終了は、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/1det/1、またはn/1for ループの検索に時間を無駄にする必要はもうありません。上記の障害スライスだけでは、すでに非終了が発生しています。したがって、これが修正されない限り、残りのプログラムを調べても意味がありません。

簡単な修正はappend/3、最後に置くことです。それはnp/1. ただし、固定長のリストを持つ再帰的な非終端記号では機能しません。

Prolog が誕生する前は、人々はまさにそのようなエンコーディングを検討していました。彼らはこの不一致に戸惑いました: 文法と述語論理の両方が宣言的形式主義です。しかし、多くの文法は非常に効率的に解析できますが、文が文法によって記述されていることを証明するには、膨大な検索スペースが必要になるようです。ここでロジックを使用するこの効果的な方法はどこにありますか?

その答えは、単純な文法を手書きのパーサーと同じくらい効率的に解析できる特定のエンコーディングであり、それが Prolog を生み出しました。今日まで、このエンコーディングは Prolog で定句文法を実装するために使用されています。これがどのように行われるかは、@WouterBeeksの回答を参照してください。

于 2014-10-25T12:05:58.960 に答える