Пролог объединяет переменную с термином, затем забывает об объединении - PullRequest
0 голосов
/ 10 февраля 2019

У меня есть следующий предикат, который я написал для распознавания, когда два списка совпадают, за исключением того, что два элемента с индексами 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

Я не сомневаюсь, что есть лучший способ поменять местами два элемента (возможно, рекурсивно), но я хотел бы знать,почему это происходит и как это исправить;Мне явно не хватает некоторых знаний Пролога.

Спасибо!

1 Ответ

0 голосов
/ 10 февраля 2019

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))).

Test:

?- swapped(0, 1, [1,2,3], L).
L = [2, 1, 3].

В SWI-Prolog иногда лучший способ понять встроенную функцию - это проверить источник.Вы можете видеть, что foreach / 2 является довольно сложным предикатом ... из приглашения swipl, попробуйте ?- edit(foreach). или перейдите по ссылке на источник со страницы документа (обведено : - ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...