2009-07-08 12 views
4

私はPrologでfindall述語を実装しようとしています(これは組み込みのもので、これは割り当て用です)。何らかの理由でPROLOGルールは最初の一致のみを返します

my_findall(N,P,Pred,L) :- Pred, not(new(N,P)), !, assert(new(N,P)), my_findall(N1,P1,Pred,L1), L=[N,P,L1], retract(new(N,P)). 
my_findall(_,_,_, []). 

それだけで私に最初のソリューションを提供してmy_findallへの2回目の呼び出しが失敗した場合のように、そこに停止して次のように

は、それが書かれています。私が理解しているように、バックトラッキングの仕組みは、Pred(N、P)を呼び出すためのすべてのオプションを含むべきすべての可能なオプションを調べる必要があります。アサートされていれば)、他のオプションをすべて試してから、my_findall(()、_、[])をあきらめてください。

これは機能しない場合、ソリューションを完全に書き換えることなくこの種の動作を強制する方法はありますか?

+0

どのプロログインタプリタを使用していますか? – liori

+0

組み込みfindallはfindall/3とfindall/4です。どちらを実装しようとしていますか? – Kaarel

答えて

5

あなたのPredにはバインドされていない変数が含まれています。最初の繰り返しでPredを呼び出すと、これらの変数は最初に取り得る値にバインドされます。再帰的なステップでは、Predはすでにバウンド変数を持ち、値を変更することはできません。だから...この解決策は動作しません。 SWI-プロローグから

トレース(私はいくつかの理由のためにアイテム/ 2に新しい/ 2の名前を変更しなければならなかった):

第1レベル(呼び出し:my_findall(A、B、部材(P(A、B)を、 [p(1,2)、p(3,4)])、L)。

Call: (7) my_findall(_G819, _G820, member(p(_G819, _G820), [p(1, 2), p(3, 4)]), _G840) ? creep 
    Call: (8) lists:member(p(_G819, _G820), [p(1, 2), p(3, 4)]) ? creep 
    Exit: (8) lists:member(p(1, 2), [p(1, 2), p(3, 4)]) ? creep 

私たちはp(A、B)= p(1,2)を得ました。この時点で、Aは1に、Bは2にバインドされています。

^ Call: (8) not(item(1, 2)) ? creep 
    Call: (9) item(1, 2) ? creep 
    Fail: (9) item(1, 2) ? creep 
^ Exit: (8) not(item(1, 2)) ? creep 

いいえ、項目(1,2)はデータベースにありません。

^ Call: (8) assert(item(1, 2)) ? creep 
^ Exit: (8) assert(item(1, 2)) ? creep 

今のアイテム(1,2)が該当します。再帰呼び出し:

Call: (8) my_findall(_L215, _L216, member(p(1, 2), [p(1, 2), p(3, 4)]), _L199) ? creep 

のは、別のソリューションを取得してみましょうPREDん:

Call: (9) lists:member(p(1, 2), [p(1, 2), p(3, 4)]) ? creep 
          ^^^^^^^ 

は、下線付きの作品を参照してください?

この手法を使用するには、PredをコピーしてNとPを新しい変数に再帰的に変更する必要があります。すべての繰り返しに対して、NとPの新しいペアを作成する必要があります。copy_term/2(http://www.swi-prolog.org/pldoc/doc_for?object=copy_term%2f2)を確認してください。

関連する問題