2017-03-10 6 views
0

私は特定のリストから数字Xを削除し、Xなしでリストを返すプロローグルールを実装しようとしていました。しかし、正しい結果を得た後、元のリストを結果として得る代わりに、私のコードで問題がどこにあるかを把握します。希望の番号が削除されたリストを取得した後に、元の結果が再び表示されるのはなぜですか?

remove1(X,[],[]). 
remove1(X,[X|T],T). 
remove1(X,[H|T],[H|R]):- 
    X \= H, 
    remove1(X,T,R). 
remove1(X,[H|T],[H|T]):- 
    \+member(X,T). 
+0

Prologは最後のブランチをバックトラックして取ります。とにかく最後のブランチを使うのはなぜですか? –

答えて

1

例を参考にしてみましょう。 2[1,2,3]から削除するとします。プロローグは、最初の答えを見つけた後2はそれ尾T=[3](のメンバーであれば、それは、チェックをバックトラック

remove1(2,[1,2,3],R): 
    fail. % clause 1 
    fail. % clause 2 
    2 \= 1, remove1(2,[2,3],R'): % clause 3 
     fail. % clause 1 
     R = [1,3] % clause 2 
     2 \= 2... fail. % clause 3 
     \+member(2,[3]),R=[1,2,3] % clause 4 
    \+member(2,[2,3])... fail. % clause 4

(太字に入れ答え)

:そして、Prologは、このようにそれを評価します。そうではありません)。したがって、[1,2,3]も答えであると回答します(最後の節に基づいて)。

なぜ私が最後の節を追加したのか不思議です。 2が見つからない場合、Prologはリストに回答していました。したがって、プログラム:

remove1(X,[],[]). 
remove1(X,[X|T],T). 
remove1(X,[H|T],[H|R]):- 
    X \= H, 
    remove1(X,T,R). 

でも十分でしょう。

ただし、1つのオカレンス「」が削除された場合にのみ、照会には「」が続くようにするには、最初の照会も削除する必要があります。だから、:

remove1_force(X,[X|T],T). 
remove1_force(X,[H|T],[H|R]):- 
    X \= H, 
    remove1(X,T,R). 

両方の述部のみがリストにX最初の発生を削除します。だからremove1_force(1,[1,2,3,1,2,3],R)。回答は1つだけです:R = [2,3,1,2,3]

1

基本的に、最初の節と最後の節は不要です。最後の節は、間違った結果が出てくる部分です。

これはもう1つの「テキストブック」述語であると思われ、通常はselect/3と呼ばれます。 [スターリング&シャピロ]、67ページ、中に教科書の定義はSWI-Prolog library implementationと同一であり、このようなものになる:あなたはそれがどんなヘルパー述語を必要としないと本当の関係があることがわかります

%! select(?Elem, ?List1, ?List2) 
% 
% Is true when List1, with Elem removed, results in List2. 

select(X, [X|Tail], Tail). 
select(Elem, [Head|Tail], [Head|Rest]) :- 
    select(Elem, Tail, Rest). 

を。例えば試してみてください。

?- select(X, [1,2,3], R). 

かさえ:

?- select(X, List, Rest), numbervars(List). 

numbervars/1だけのソリューションが少し読みやすくなり)

この定義は、それが、うまく...ためであるほど一般的ですそれは一般的な定義です。最初の句は「選択」を行い、2番目の句は再帰的なステップを定義します。

[スターリング&シャピロ]:スターリングL、シャピロEY。 Prologの芸術:高度なプログラミング技術。 MITプレス。 1994.

関連する問題