1

どうしたの?
私はPrologでいくつかの本当に奇妙な問題を抱えています。
特定のインデックスでリスト内の要素を置き換える再帰ルールが常に機能するとは限りません。
私のルールは次のようになります。

% Base rule - Stops when index is 1 and replaces the head with the element.
replaceAtIndex(1, _element, [_|_tail], [_element|_tail]).

% Recursive rule - Enter recursion for tail as long as index is larger than 1.
replaceAtIndex(_index, _element, [_head|_tail], [_head|_new_tail]):-
    _index > 1,
    _new_index is _index - 1,
    replaceAtIndex(_new_index, _element, _tail, _new_tail).

プログラム内からデバッガーを使用すると、インデックスが何であっても常に2番目のルールが呼び出されますが、プログラムの外部でまったく同じコマンドを実行すると、完全に機能します。インデックス1に到達しますが、2番目のルールを呼び出し、最初のルールをバックトラックして試行せず、最後まで失敗します...

replaceAtIndexを呼び出すルールは次のようになります。

level_replace_block_value(_x, _y, _value):-
    current_level(_level_number, _width, _height, _blocks, _drawX, _drawY),
    coordinates_to_index(_x, _y, _index),
    _index_in_list is _index + 1, % the replaceAtIndex is not 0 terminated
    replaceAtIndex(_index_in_list, _value, _blocks, _new_blocks),
    retractall(current_level(_,_,_,_,_,_)),
    assert(current_level(_level_number, _width, _height, _new_blocks, _drawX, _drawY),
    graphics_update_block_value(_x, _y).

インデックスを111として呼び出しをデバッグしているとき。定数111に
置き換えているときは、機能します。_index_in_list

なぜそれが起こるのか、誰かが手がかりを持っているかもしれませんか?

4

4 に答える 4

0

バックトラッキングが行われる方向を誤解していると思われます。

への呼び出しでは、最初の「基本」ルールが最初に試行されreplaceAtIndex/4ます。最初のルールの「先頭」で呼び出しが単一化できないために失敗した場合、Prolog エンジンは 2 番目のルールに戻ります。[統合の失敗は、最初の引数 (インデックス) が 1 と異なるか、3 番目の引数が空でないリストではないことが原因である可能性があります。]

バックトラッキングは決して逆方向には進みません。2 番目のルールが試行されて失敗した場合、呼び出しは失敗します。

もちろん、再帰的な定義によって事態は複雑になります。2 番目のルールの適用に成功すると、 への新しい呼び出しがreplaceAtIndex/4必要になります。これは、Prolog エンジンに関する限り、最初のルールに戻ることによってその目標を達成しようと試み始める必要があります。

最初のルールにカットを追加することをお勧めします。構造上、最初のルールが成功すると、2 番目のルールは決して成功しないからです。しかし、これは単なる効率の問題です...それ以上の解決策が得られない選択ポイントを開いたままにしておくのはなぜでしょうか?

replaceAtIndex(1, _element, [_|_tail], [_element|_tail]) :- !.

追加:あなたのコードが Amzi で動作することを確認しました! 次のような呼び出しでプロローグします。

?- replaceAtIndex(3, 0, [1,2,3,4,5,6], L).

L = [1, 2, 0, 4, 5, 6] ;
no
?- 

もちろん、コードがスタンドアロン/インタープリター モードで呼び出された場合にも成功が見られます。

したがって、渡される「インデックス」引数は整数ではなく、浮動小数点数であると思われる必要があります。整数 1 は、数学的に等しい場合でも、浮動小数点 1.0 と統合されません。

述語is_integer/1を使用して、Amzi でこれをテストできます! プロローグ。関数integer(X)を使用して、(存在しない) 小数部分を切り捨てることにより、実数 1.0 を整数 1 に変換できます。

于 2012-02-09T16:10:58.063 に答える
-1

_index_in_listに設定してみてください1。その場合、最初のルールが呼び出されませんか?

2 番目のルールが呼び出される理由は確かに、_index_in_listがより大きいため111ですか? 最初のパラメーターが示すように、最初のルールは - のみを扱います。11111

_index_in_listを定数に置き換える111と機能します。

何?最初のルールが呼び出されるということですか? どうしてですか、最初のパラメータは1.

于 2012-02-09T12:41:25.313 に答える
-1
replaceAtIndex(I, Value, List, Result) :-
    RI is I-1,
    findall(Before, (nth0(B, List, Before), B < RI), Before),
    findall(After, (nth0(A, List, After), A > RI), After),
    append([Before, [Value], After], Result).


?- replaceAtIndex(3,0,[1,2,3,4,5,6], L).
L = [1, 2, 0, 4, 5, 6].
于 2012-02-12T08:21:37.107 に答える