Prolog称错误的规则。没有正确回溯

时间:2012-02-09 12:13:38

标签: debugging prolog call rule backtracking

什么事? 我和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).

当我在我的程序中使用调试器时,我看到它始终调用第二条规则,无论索引是什么,但是当我在程序外执行完全相同的命令时,它运行得非常好。它到达索引1但是调用第二个规则,并且没有回溯并尝试第一个规则并且一直失败...

调用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 个答案:

答案 0 :(得分:1)

使用内置谓词&amp;<select name='cat1'> <option value='0'>Select one</option> <option value='1'>little</option> <option value='2'>good</option> </select> <select name='soft1'> <option value=''>Select one</option> <option value='W'>Word</option> <option value='E'>Excel</option> <option value='PP'>Power Point</option> </select> <br /> <select name='cat2'> <option value='0'>Select one</option> <option value='1'>little</option> <option value='2'>good</option> </select> <select name='soft2'> <option value=''>Select one</option> <option value='W'>Word</option> <option value='E'>Excel</option> <option value='PP'>Power Point</option> </select> <br /> <br />same_length/2保留

length/2

首先,让我们在a previous answer中运行@magus用于此问题的示例查询:

append/3

以后实例化列表项时是否有效?

replace_at(I,X,Xs0,Xs2) :-
   same_length(Xs0,Xs2),
   append(Prefix,[_|Xs1],Xs0),
   length([_|Prefix],I),
   append(Prefix,[X|Xs1],Xs2).

是的!如果索引不是具体的整数,而是未绑定的逻辑变量,该怎么办? 有用吗?

?- replace_at(3,0,[1,2,3,4,5,6],Xs).
Xs = [1,2,0,4,5,6] ;
false.

确实如此!使用单调代码,即使是非常常见的查询,我们也能获得逻辑上合理的答案

答案 1 :(得分:0)

我怀疑你误解了回溯发生的方向。

第一个&#34;基地&#34;对replaceAtIndex/4的任何调用都将首先尝试规则。如果失败,由于与&#34; head&#34;的呼叫不一致。第一条规则,然后Prolog引擎回溯到第二条规则。 [统一失败可能来自第一个参数(索引)不同于1或第三个参数不是非空列表。]

回溯永远不会走向另一个方向。如果第二条规则尝试失败,则呼叫失败。

当然,递归定义使事情复杂化。应用第二条规则的成功需要对replaceAtIndex/4进行新的调用,就Prolog引擎而言,必须从第一条规则开始尝试满足该目标。

我建议在第一条规则中添加一个剪切,因为按照构造,第二条规则永远不会成功。但这只是一个效率问题......为什么要让选择点保持开放,永远不会产生任何进一步的解决方案呢?

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

已添加:我确认您的代码在Amzi中有效! Prolog这样的电话:

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

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

但是当你以独立/解释模式调用代码时,你也会看到成功。

所以我不得不怀疑&#34;索引&#34;传入的参数不是整数,而是浮点数。整数1不会与浮点1.0统一,即使它们在数学上是相等的。

您可以使用谓词 is_integer / 1 在Amzi中对此进行测试!序言。函数整数(X)可用于通过截断(不存在的)小数部分将实数1.0转换为整数1。

答案 2 :(得分:-1)

_index_in_list设置为1。那么第一条规则不会被调用吗?

如果您的_index_in_list111111大于1,请确保调用第二条规则的原因是什么?第一条规则只处理1 - 作为第一个参数说明。

  

当我用常量_index_in_list替换111时   的工作原理。

什么?你的意思是第一个规则被调用?怎么可能,第一个参数是1

答案 3 :(得分:-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].