我编写了以下谓词,以识别两个列表相同时的区别,除了索引I1
和I2
的两个元素被交换之外:
swapped(I1, I2, List, NewList) :-
% The lists are the same length and the two indices are swapped.
same_length(List, NewList),
nth0(I1, List, V1), nth0(I2, List, V2),
nth0(I1, NewList, V2), nth0(I2, NewList, V1),
% All the other indices remain the same.
proper_length(List, Length), Lim is Length - 1,
numlist(0, Lim, Indices),
forall((member(I, Indices), I \= I1, I \= I2),
(nth0(I, List, V), nth0(I, NewList, V))).
以下swipl
输出显示了我的问题:
?- swapped(0, 1, [1,2,3], L).
L = [2, 1, _G5035].
?- swapped(0, 1, [1,2,3], [2,1,3]).
true.
?- swapped(0, 1, [1,2,3], [2,1,4]).
false.
鉴于它可以识别出3
是唯一正确的术语,为什么它为第三个元素返回一个变量,而不仅仅是3
?这些是跟踪发生的最后四个部分,然后被遗忘了:
Call: (10) lists:nth0(2, [2, 1, _G6121], 3) ? creep
Exit: (10) lists:nth0(2, [2, 1, 3], 3) ? creep
^ Exit: (8) forall(user: (member(_G6145, [0, 1, 2]), _G6145\=0, _G6145\=1), user: (nth0(_G6145, [1, 2, 3], _G6162), nth0(_G6145, [2, 1, _G6121], _G6162))) ? creep
Exit: (7) swapped(0, 1, [1, 2, 3], [2, 1, _G6121]) ? creep
我毫不怀疑有一种更好的方式来交换两个元素(也许是递归的),但是我想知道为什么会发生这种情况以及如何解决它;我显然缺少一些Prolog知识。
谢谢!
答案 0 :(得分:5)
forall / 2是所谓的'failure driven loop'。然后在循环之间取消实例化。
在SWI-Prolog中,有foreach / 2,可以解决您的第一个查询问题。
...
numlist(0, Lim, Indices),
foreach((member(I, Indices), I \= I1, I \= I2),
(nth0(I, List, V), nth0(I, NewList, V))).
测试:
?- swapped(0, 1, [1,2,3], L).
L = [2, 1, 3].
在SWI-Prolog中,有时候了解内建函数的更好方法是检查源代码。您可以从swipl提示符中看到foreach / 2是一个相当复杂的谓词...,尝试?- edit(foreach).
,或访问doc页面(带圆圈的:-)中的源链接。