あなたが尋ねる:
なぜですか?- is_fakt(L)
...しかし、いくつかの結果 が答えた後、それはハングします。
あなたは数を言います。SPACEその数は、ループのその瞬間に到達するために押す62回です。かなり長いですね。そして、あなたのプログラムは小さいです。より大きなプログラムで同じことをする機会をどのようにして得ることができますか?心配しないでください、助けがあります。しかし、あなたは別の角度からプログラムを見る必要があります。
Prologでは、具体的なクエリを非常に正確に実行することはほぼ不可能です。インターリーブされた2種類の制御フローと、存在する必要はないが後で「入ってくる」奇妙なデータ構造があります。時折。そのすべてが、非常に詳細に満ちている可能性のある実行トレースの真のパノラマを開き、あなたの心はあふれます—さらに悪いことに:あなたの心はまだふりをしますあなたはすべてを理解しますが、事実上あなたは理解しません。そして、バグはあなたのプログラムで大きなパーティータイムを持っています。これらのバグは、将来のある時点で噛み付きますが、バグごとにのみ噛み付きます。それは非常に意気消沈する可能性があります。結局のところ、プログラムは非常に小さいので、(命令型言語の基準では)理解しやすいはずです。しかし、その後、Prologプログラムは、他の言語では非常に複雑な問題に対して非常にコンパクトになる傾向があります。
トレーサーを使って、私が何を意味するのかを確認してください。あなたはあらゆる種類のことが起こっているのを見るでしょう。そしてそれらのほとんどは無関係です。
幸いなことに、Prologを理解する方法はいくつかありますが、ここでは、言語自体の優れたプロパティに依存する必要があります。非終了の理由をローカライズするために、最良の方法は、失敗スライスの検討を開始することです。プログラムに目標を追加することにより、プログラムから失敗スライスを取得false
します。それでも結果のプログラムが終了しない場合は、元のプログラムも終了しない理由があります。
考えてみてください。あなたのプログラムを理解しようとする代わりに、私たちは人間がはるかに優れていることをします。知識に基づいた推測をすることです。その推測はうまくいかない可能性がありますが、簡単に確認できます。最初は、推測するのがかなりひどいでしょう。すぐに、体系的に多くのことができることがわかります。現在無関係になるすべてのコードは、ストライクスルーです。
:-use_module(library(clpfd))。
fact(扱われた= A):-0..1のA。
fact(numYears = B):-0..supのB、false。
fact(numDrugs = C):-0..supのC、false。
fact(treatment2 = D):-0..1のD、false。
fact(cParam = E):-0..4のE、false。
is_differentfact(X、X):-false。
is_differentfact(Element = _、OtherElement = _):-
dif(Element、OtherElement)。
is_fakt([])。
is_fakt([X | Xs]):-
fact(X)、
maplist(is_differentfact(X)、Xs)、
is_fakt(Xs)。
私たちは何を得ましたか?問題をはるかに速く絞り込むことができます。
?-is_fakt(Xs)。
Xs = [];
Xs =[処理済み=_G180099]、
_G180099 in 0..1;
**ループ**
続行する前に、私はあなたが何を意味するのかを理解しようとしますis_fakt/1
。あなたはおそらく意味します:それらの名前によるすべての事実、そして何も繰り返されていないことを確認してください。これで、という名前のファクトtreated
しかないため、長さ1のリストしか作成できません。次にループします。
あなたが言った:
Prologがのすべての可能な値を返すことができない理由がわかりませんX
。
うるさいのは、それは真実ではありません。Prologはのすべての可能な値を列挙しX
ました。しかし、それは終了しませんでした。
((考慮すべきいくつかの注意:本当にその方法でそのリストを取得したいですか?すべての順列を取得します!長さnのリストを使用すると、 n!異なる回答が得られます。n= 10の場合、3628800です。これは何が欲しいですか?おそらくそうではありません。))
しかし、最初に、非終了の正確な理由を特定することに固執しましょう。
理由をよりよく特定するために、すべての回答を「オフ」にしましょう。したがって、is_fakt(L),
false
代わりに次のようにクエリを実行します。
:-use_module(library(clpfd))。
fact(扱われた= A):-0..1のA。
fact(numYears = B):-0..supのB、false。
fact(numDrugs = C):-0..supのC、false。
fact(treatment2 = D):-0..1のD、false。
fact(cParam = E):-0..4のE、false。
is_differentfact(X、X):-false。
is_differentfact(Element = _、OtherElement = _):-
dif(Element、OtherElement)。
is_fakt([]):- false。
is_fakt([X | Xs]):-
fact(X)、
maplist(is_differentfact(X)、Xs)、false、
is_fakt(Xs)。
これは最小限の障害スライスです。maplist/2
そもそも終わらないのです。あなたのアイデアはX
、のファクト名とは異なるファクト名を持つようにすることでしたXs
。しかし、Xs
バインドされていない場合、それは決して終了しません。試してみよう:
?-maplist(is_differentfact(X)、Xs)。
Xs = [];
X =(_G496 = _G497)、
Xs = [_G508 = _G509]、
dif(_G496、_G508);
X =(_G552 = _G553)、
Xs = [_G564 = _G565、_G570 = _G571]、
dif(_G552、_G570)、
dif(_G552、_G564);
X =(_G608 = _G609)、
Xs = [_G620 = _G621、_G626 = _G627、_G632 = _G633]、
dif(_G608、_G632)、
dif(_G608、_G626)、
dif(_G608、_G620);
X =(_G664 = _G665)、
Xs = [_G676 = _G677、_G682 = _G683、_G688 = _G689、_G694 = _G695]、
dif(_G664、_G694)、
dif(_G664、_G688)、
dif(_G664、_G682)、
dif(_G664、_G676);
X =(_G720 = _G721)、
Xs = [_G732 = _G733、_G738 = _G739、_G744 = _G745、_G750 = _G751、_G756 = _G757]、
dif(_G720、_G756)、
dif(_G720、_G750)、
dif(_G720、_G744)、
dif(_G720、_G738)、
dif(_G720、_G732)..。
見るのはあまり良くありません...しかし、私たちはそれをより良くすることができます:
?-maplist(is_differentfact(X)、Xs)、false。
**ループ**
だからそれはループします。これが非終了の理由です。問題を修正するには、障害スライスの残りの表示部分で何かを行う必要があります...
詳細については、failure-sliceとタグ付けされた他の説明を調べてください