Prolog将一个变量与一个术语统一起来,然后忘记统一

Jxe*_*xek 3 prolog

我有以下谓词,我写的是为了识别两个列表是相同的,除了索引处的两个元素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))).
Run Code Online (Sandbox Code Playgroud)

以下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.
Run Code Online (Sandbox Code Playgroud)

为什么它会为第三个元素返回一个变量而不仅仅是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
Run Code Online (Sandbox Code Playgroud)

我不怀疑有更好的方法来交换两个元素(可能递归)但我想知道为什么会发生这种情况以及如何解决它; 我显然缺乏一些Prolog的知识.

谢谢!

Cap*_*liC 5

forall/2是所谓的" 故障驱动循环 ".然后在循环之间撤消实例化.

在SWI-Prolog中,有foreach/2,可以解决第一个查询的问题.

...
numlist(0, Lim, Indices),
foreach((member(I, Indices), I \= I1, I \= I2),
       (nth0(I, List, V), nth0(I, NewList, V))).
Run Code Online (Sandbox Code Playgroud)

测试:

?- swapped(0, 1, [1,2,3], L).
L = [2, 1, 3].
Run Code Online (Sandbox Code Playgroud)

在SWI-Prolog中,有时理解内置的更好方法是检查源.您可以看到foreach/2是一个相当复杂的谓词...从swipl提示,尝试?- edit(foreach).,或者按照文档页面中的源链接(带圆圈的: -).

  • 很高兴看到使用`edit(foreach).`请保留这些提示. (2认同)