少し言い換えてみましょう。述語を複数のインスタンス化パターンで使用したいので、「値とリストを指定したプロシージャは、リスト内のその値のすべての出現を削除します」は、それがどのように動作するかを定義しませんその他の場合。したがって、「2番目と3番目の引数がリストL1の場合、述語はtrueであり、最初の引数のすべての出現を無視すると、L1はL2と同じリストになります」のようなものが必要になる可能性があります。
現在、複数の可能なインスタンス化を使用して述語を作成する方法は2つあります。var/1
andなどのメタロジカル述語を使用してground/1
、それぞれにコードを記述したり(おそらく、その特定のインスタンス化に最適化されたコードを記述したりできます)、プロパティを論理的に定義するコードを記述したりできます(これはより困難な場合があります)。
この場合、次のようなことができます。
del(_, [], []).
del(X, [X|L1], L2):-
del(X,L1,L2).
del(X, [H|L1], [H|L2]):-
X\==H,
del(X,L1,L2).
これは次の動作をします:
19 ?- del(1, [1,2,3], X).
X = [2, 3] ;
false.
1,2,3,
20 ?- del(1, [1,2,3], [2,3]).
true ;
false.
21 ?- del(X, [1,2,3], [2,3]).
X = 1 ;
false.
22 ?- del(X, [1,2,3], Y).
X = 1,
Y = [2, 3] ;
X = 2,
Y = [1, 3] ;
X = 3,
Y = [1, 2] ;
Y = [1, 2, 3] ;
false.
23 ?- del(X, P, Y).
P = Y, Y = [] ;
P = [X],
Y = [] ;
P = [X, X],
Y = [] ;
P = [X, X, X],
Y = [] ;
P = [X, X, X, X],
Y = [] ;
P = [X, X, X, X, X],
Y = [] ;
P = [X, X, X, X, X, X],
Y = [] .
最後の呼び出しに関して; prologは、深さ優先アルゴリズムが使用されるために大きくなるXのリストを返します。を使用length/2
することで、幅優先の結果を得ることができます(_Gは、変数がインスタンス化されていないことを意味します(何でもかまいません)):
24 ?- length(P,N), del(X, P, Y).
P = [],
N = 0,
Y = [] ;
P = [X],
N = 1,
Y = [] ;
P = [_G548],
N = 1,
Y = [_G548] ;
P = [X, X],
N = 2,
Y = [] ;
P = [X, _G551],
N = 2,
Y = [_G551] ;
P = [_G548, X],
N = 2,
Y = [_G548] ;
P = [_G548, _G551],
N = 2,
Y = [_G548, _G551] ;
P = [X, X, X],
編集:@chacが指摘したように、最初のリストに(少なくとも)1つの重複要素がある場合、上記の述語は正しく動作しません。
?- del(X,[1,2,1],Y).
X = 1,
Y = [2] ;
X = 2,
Y = [1, 1] ;
X = 1,
Y = [1, 2] ; <----- wrong
Y = [1, 2, 1].
これは、実際には変数に制限を課していない\==/2
ためです。\=/2
これは、3番目の句のルールの順序を切り替えることで解決できます。
del(_, [], []).
del(X, [X|L1], L2):-
del(X,L1,L2).
del(X, [H|L1], [H|L2]):-
del(X,L1,L2),
X\==H.
4 ?- del(X,[1,2,1],Y).
X = 1,
Y = [2] ;
X = 2,
Y = [1, 1] ;
Y = [1, 2, 1] ;
false.
ただし、これは、述語が末尾再帰ではなくなったことを意味します。Xであってはならない値のリストを保持できることを修正するには、次のようにします。
del(X,L1,L2):-
del(X,L1,L2,[]).
del(X, [], [], NotX):-
\+ member(X,NotX).
del(X, [X|L1], L2, NotX):-
del(X,L1,L2,NotX).
del(X, [H|L1], [H|L2], NotX):-
X\==H, % <--- optional; stops the execution earlier (saving time)
del(X,L1,L2,[H|NotX]).
ただし、以下によると、末尾再帰バージョンは実際には低速です。
?-time(forall((between(1,50,N),length(X,N),del2(1,X,[2,3,2,3])),true)).
% 25,600,793 inferences, 5.468 CPU in 5.548 seconds (99% CPU, 4682134 Lips)
true.
?- time(forall((between(1,50,N),length(X,N),del_tr(1,X,[2,3,2,3])),true)).
% 37,346,143 inferences, 6.426 CPU in 6.428 seconds (100% CPU, 5811563 Lips)
true.
それでも、+-+は機能しません(無限ループに陥ります)。しかし、なぜ?問題は句の順序にあります。del(1、L1、[2])は、最初にXをL1の先頭に「追加」するルールを適用し、次に同じルールを永久に適用します。これは(再び)を使用して対抗することができますlength/2
:
?- length(X,2), del(1,X,[2]).
X = [1, 2] ;
X = [2, 1] ;
false.
または、句の順序を変更することもできます。
del(_, [], []).
del(X, [H|L1], [H|L2]):-
X\==H,
del(X,L1,L2),
X\==H.
del(X, [X|L1], L2):-
del(X,L1,L2).
length/2
それがなければ、プロローグは深さ優先探索を行うので、まだ再び役立つかもしれません:
?- del(1,X,[2]).
X = [2] ;
X = [2, 1] ;
X = [2, 1, 1] ;
X = [2, 1, 1, 1] ;
X = [2, 1, 1, 1, 1] ;
X = [2, 1, 1, 1, 1, 1] ;
X = [2, 1, 1, 1, 1, 1, 1]
もちろんlength/2
、他のインスタンス化パターンに影響を与えないため、ラッパー述語に組み込むことができます。