我从http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlse25得到了这个反向函数:
accRev([H|T],A,R):- accRev(T,[H|A],R).
accRev([],A,A).
rev(L,R):- accRev(L,[],R).
这适用于
之类的内容?- rev([a,b,c], R).
R = [c,b,a]
但是我得到了一个堆栈溢出:
?- rev(L, [c,b,a]).
为什么会导致堆栈溢出?有没有办法使两者都有效?:
答案 0 :(得分:4)
?- rev(L, [c,b,a]).
为什么会导致堆栈溢出?
Sssh ......你正在加速Prolog引擎。
实际上有两个原因:第一,查询没有终止。然后,它以相当无效的方式搜索解决方案。
让我"解决"通过首先解决第二个原因来解决这个问题。只需交换accRev/3
的两个条款。这改变了答案:
?- rev(L, [c,b,a]).
ERROR: Out of local stack
到
?- rev(L, [c,b,a]).
L = [a, b, c]
很好 - 或者差不多。请注意,Prolog没有在解决方案的末尾添加.
。这意味着它说:想要更多这个?因此,输入;
即可获得:
?- rev(L, [c,b,a]).
L = [a, b, c] ;
ERROR: Out of global stack
所以我们几乎"解决了这个问题。我们找到了解决方案,但Prolog仍未终止。这很好地说明了纯Prolog程序的一个属性:
交换条款可能会影响解决方案/答案的找到方式,但不会影响终止。
确保目标实际终止的最佳方法是关闭"关闭"我们通过添加false
获得的所有答案:
?- rev(L, [c,b,a]), false. ERROR: Out of global stack
无论子句如何排列,此错误现在都以相同的方式发生。事实上,原因可以缩小到以下failure-slice:
rev(L,R):- accRev(L,[],R), false.accRev([],A,A) :- false. accRev([H|T],A,R):- accRev(T,[H|A],R), false.
注意R
,它只是进一步传递。因此它对终止没有任何影响。
但请注意,L
和R
的长度相同......
所以也许首先考虑same_length/2
,它可以直接解决这个问题。
same_length([], []).
same_length([_|L], [_|R]) :-
same_length(L, R).
rev_better(L, R) :-
same_length(L, R),
rev(L, R).
或者,如果您进入"效率",只需观察same_length/2
可以直接折叠:
rev_folded(L, R) :-
accrev(L, [],R, R).
accrev([], R,R, []).
accrev([E|L], R0,R, [_|Rx]) :-
accrev(L, [E|R0],R, Rx).