多くの述語は、基本的に何らかの形式の推移閉包を使用しますが、終了にも対処する必要があることを発見するだけです。これを一度だけ永遠に解決してみませんかclosure0/3
:
:- meta_predicate closure0(2,?,?).
:- meta_predicate closure(2,?,?).
:- meta_predicate closure0(2,?,?,+). % internal
closure0(R_2, X0,X) :-
closure0(R_2, X0,X, [X0]).
closure(R_2, X0,X) :-
call(R_2, X0,X1),
closure0(R_2, X1,X, [X1,X0]).
closure0(_R_2, X,X, _).
closure0(R_2, X0,X, Xs) :-
call(R_2, X0,X1),
non_member(X1, Xs),
closure0(R_2, X1,X, [X1|Xs]).
non_member(_E, []).
non_member(E, [X|Xs]) :-
dif(E,X),
non_member(E, Xs).
この定義を推移閉包の実装に使用できない場合はありますか?
なぜ dif/2 なのですか?
@WouterBeek のコメントに詳細に答えるには: dif/2
oriso_dif/2
は、潜在的な問題を表示または通知できるため、理想的です。ただし、現在の実装では、トップレベルのループが実際の問題を隠していることがよくあります。closure0(\_^_^true,a,b)
確かにそれ自体が非常に問題のある目標を考えてみましょう。次のシステムを使用する場合、実際の問題は直接目に見えません。
| ?- closure0(\_^_^true,a,b). % SICStus
yes
?- closure0(\_^_^true,a,b). % SWI
true ;
true ;
true ...
どちらの最上位ループも、実際に見たいもの、つまりダングリング制約を示していません。SICStus では、置換を生成するために疑似変数が必要です。SWI では、クエリを でラップする必要がありますcall_residue_vars/2
。このようにして、制約が付加されているすべての変数が表示されるようになりました。
| ?- closure0(\_^_^true,a,b), Alt=t. % SICStus
Alt = t ? ;
Alt = t,
prolog:dif(_A,a),
prolog:dif(b,_A) ? ;
Alt = t,
prolog:dif(_A,a),
prolog:dif(_B,_A),
prolog:dif(_B,a),
prolog:dif(b,_B),
prolog:dif(b,_A) ...
?- call_residue_vars(closure0(\_^_^true,a,b),Vs). % SWI
Vs = [] ;
Vs = [_G1744, _G1747, _G1750],
dif(_G1744, a),
dif(b, _G1744) ;
Vs = [_G1915, _G1918, _G1921, _G1924, _G1927, _G1930, _G1933],
dif(_G1915, a),
dif(b, _G1915),
dif(_G1921, _G1915),
dif(_G1921, a),
dif(b, _G1921) ...