2

プロローグ、リスト、再帰全体をよりよく理解するために、私は自分に割り当てたさまざまな単純なタスクを実行しています。特に、リストからdoubleエントリを削除しています。

ルールを定義しました:

is_on(Item, [Ah|At]) :- Ah = Item; is_on(Item, At).

これは、「アイテム」がリストXにあるかどうかをチェックします。したがって、これを拡張してfilter_double述語も定義できると思いました。

filter_doubles([Ah|At], Result) :-
    (not(is_on(Ah, At)) ->
        Result = [Ah|Result]
    ;
        filter_doubles(At, Result)
    ).

これは私にとって完全に理にかなっています。リストの残りの部分(テール)でAhが発生しない場合は、リストの作成を使用して結果の先頭にaを追加します。それ以外の場合は、リストの残りの部分を繰り返します。どうやらPrologはそうではないと考えています:

47 ?- filter_doubles([1,2,3,3,4,2,1,1], Z).
Z = [3|**]. 

私はこれについてあまりにも必須だと思っていますか?

4

2 に答える 2

3

論理プログラミングでは、述語の再帰は複数のルールで処理されることがよくあります。最初の規則は、再帰の基本ケース、つまりその停止条件を記述します。他のルール、またはおそらく 2 番目のルールは、再帰的なステップを記述します。

したがって、is_onルール (名前を に変更しましcontainsた) は通常、次のように記述されます。

contains(Item, [Item | _]).
contains(Item, [_ | Tail]) :- contains(Item, Tail).

述語は、同様のfilter_double書き換えを受ける可能性があります。まず、空のリストは空の結果に対応します。

filter_doubles([], []).

次に、リストの でItemが発生した場合Rest、リストの を繰り返し、Restの出現を削除しItemます。

filter_doubles([Item | Rest], Result) :-
    contains(Item, Rest), !,
    filter_doubles(Rest, Result).

最後に、リストItemの に が発生しない場合Rest(前のルールがそのケースに対して既にチェックアウトされているため)、Itemリスト構築を使用して結果の先頭に自由に配置しRest、リストの のフィルタリングに進むことができます。 .

filter_doubles([Item | Rest], [Item | Tail]) :- filter_doubles(Rest, Tail).

のような式で累積を実行しようとすると、Result = [Ah|Result]Prolog は無限再帰的なデータ構造を作成することに注意してResultください。頭と尾などを持つリストと統合されます。AhResultAhResultAhResult

于 2011-03-07T10:05:37.647 に答える
2

両方の分岐で再帰が必要であり、基本ケースが必要です。

filter_doubles([], []).
filter_doubles([X|L], Result) :-
    (memberchk(X,L) ->
        filter_doubles(L, Result)
    ;
        filter_doubles(L, Result0),
        Result = [X|Result0]
    ).

Result = [Ah|Result]実際、命令的思考の場合のようです。Prolog で意味するのは、「2 番目の引数としてResult持つ項で統一するResult」ことです。これは、失敗するか (チェックが発生した場合の統一で)、「有理ツリー」(ほとんどの Prolog で、ループを含むグラフ構造) を生成します。

演習: 投稿したコードを末尾再帰にします。

これにより、各項目の最後の出現以外のすべてが削除されることに注意してください。

于 2011-03-07T09:55:24.577 に答える