問題を見つけようとしましたが、うまくいきませんでした。何が問題なのか教えていただけますか?
% using accumulator
deleteall(X,Y,Zs) :- deleteall(X,Y, [], Zs).
deleteall(X, [], Zs, Zs).
deleteall(X, [X|Xs], Xs, V).
deleteall(X, [Y|Xs], [Y|Zs], V) :- deleteall(X, Xs, Zs,V).
問題を見つけようとしましたが、うまくいきませんでした。何が問題なのか教えていただけますか?
% using accumulator
deleteall(X,Y,Zs) :- deleteall(X,Y, [], Zs).
deleteall(X, [], Zs, Zs).
deleteall(X, [X|Xs], Xs, V).
deleteall(X, [Y|Xs], [Y|Zs], V) :- deleteall(X, Xs, Zs,V).
純粋な解決策については、この回答を検討してください。引数の順序が異なることに注意してください。
しかし、あなたの実際の質問は次のとおりでした:あなたのソリューションの何が問題なのですか?
Prolog 独自の方法でこれに答える方法があります。他のプログラミング言語では、意味のあるテスト ケースを見つけ出す必要があります。次に、そのようなテスト ケースを使用して、実装が機能するかどうかを確認します。もちろんPrologでも可能です。
しかし、これらのテスト ケースを把握するための実際のコストについて考えてみてください。関係全体を詳細に理解する必要があります。精神的に存在するデータ構造に関する詳細をすべて把握する必要があります。それはかなりの知的な努力です。あなたの例は非常に単純であるため、その努力はささいなことのように見えます。しかし、あちこちに追加された詳細を想像してみてください。
では、実際の関係を理解せずに述語のテスト ケースをどのように理解できるのでしょうか。
最も一般的なクエリを取り上げます。つまり、すべての引数に個別の変数があるゴールです。あなたの例では、それはdeleteall(X, Xs, Ys)
. これで作業は完了し、Prolog に空白を埋めさせることができます。
?-すべて削除(X,Xs,Ys). Xs = Ys、Ys = [] ; Xs = [X] ; 間違い。
あなたの定義では、2 つの答えが得られます。最初の回答にはXs
、空のリストになるための解決策が含まれています[]
。2 番目の回答にはXs
、1 つの要素リストになるための解決策が含まれています。そして、それはあなたの関係が説明するすべてです。
2 つ以上の要素を含むリストについてはどうでしょうか。それらに対する解決策はありません。したがって、あなたの定義はその点で具体的すぎます。
そして、2 番目の答えはすべての場合に当てはまりますYs
。たとえばdeleteall(1,[1],[2,3])
、あなたの定義によると - も成り立ちます。さらに悪いことdeleteall(1,[1],[1]).
に、まったく削除されません。したがって、あなたの定義はここでは一般的すぎます。
このすべての落とし穴はどこにあるのでしょうか? そうですね、純粋で単調なプログラムを書かなければなりません。つまり、 、 、 、および副作用のあるビルトインのような不純なビルトインは!/0
使用(\+)/1
し(\=)/2
て(\==)/2
はなりません (または非常に特別な注意を払って使用してください)。
シングルトン変数は常に疑わしいものであり、あなたの場合、 V in の意味は何deleteall(X, [X|Xs], Xs, V).
ですか?
それとは別に、なぜアキュムレータを使用しているのかわかりません。
削除されていない要素を元に戻すように割り当てられていますか? それ以外の場合は、機能するdeleteallがあります...
deleteall(_, [], []).
deleteall(X, [X|Xs], Zs) :- !, deleteall(X, Xs, Zs).
deleteall(X, [Z|Xs], [Z|Zs]) :- deleteall(X, Xs, Zs).
テスト:
?- deleteall(2,[1,2,3,54,2,1,4,2],X).
X = [1, 3, 54, 1, 4] ;
false.
あなたのコードから、統一に基づくすべて削除のセマンティクスが必要なようです (代わりに、(==)/2 を使用して等しい用語のみを削除することもできます)。すべてのリスト要素 (および削除する要素) は常に固定されていますか? そうしないと、削除する要素が部分的にインスタンス化され、リスト要素の 1 つと統合するときにさらにインスタンス化されるたびに、コードが失敗する可能性があります。この問題は、頭の統合の代わりに、たとえば本文の二重否定を使用することで解決できます。「chac」がすでに指摘したように、選択ポイントも残しています。カットまたは if-then-else を使用すると、その問題が解決します。コードを改善するもう 1 つの方法は、リストを最初の引数に移動して、Prolog の最初の引数のインデックス作成のパフォーマンスを向上させることです (もちろん、その述語への呼び出しでは、最初の引数がインスタンス化されます)。次の行に沿った定義に従います。
delete_all([], _, []).
delete_all([X|Xs], Y, Zs) :-
( \+ X \= Y ->
delete_all(Xs, Y, Zs)
; Zs = [X|Zs0],
delete_all(Xs, Y, Zs0)
).