Пролог два списка пересечения-почему он продолжает проверять?


Мне нужно найти элементы, которые существуют в обоих списках S1 и S2, и мне нужно распечатать эти элементы (R). Проблема в том, что когда я набираю bendri([a,b,c,d],[d,b,e],R), он возвращает правильный результат [b,d], но не останавливается. Если вы нажмете; символ, то он продолжает проверку снова и возвращает b, после этого - d.

Почему это происходит? Он должен только вернуться [b,d] и закончить свою работу.

bendri(S1,S2,R) :-
    skaiciavimai(S1,S2,R).

skaiciavimai([],_,[]).
skaiciavimai([First|Tail], S2, [First|Rest]) :-
    member(First, S2),
    skaiciavimai(Tail, S2, Rest).
skaiciavimai([_|Tail], S2, Rest) :-
    skaiciavimai(Tail, S2, Rest).
4 2

4 ответа:

Ваша проблема заключается в том, что третье предложение skaiciavimai/3 также успешно возвращается, даже если второе предложение успешно. Я думаю, вы хотите пропустить третье предложение, если второе предложение будет успешным.

Для этого можно добавить галочку в третьем предложении:

skaiciavimai([First|Tail], S2, Rest) :-
    \+ (member(First, S2)),
    skaiciavimai(Tail, S2, Rest).
Таким образом, третье предложение не выполняется, если глава первого списка находится в S2.

Простая история: ; означает, что пролог должен искать альтернативы, и поскольку bendri(A,B,C) определяется как "C является списком элементов, которые встречаются как в A, так и в B" (согласно вашему определению), он напечатает все возможные результаты. Вы можете увидеть это на trace ниже (добавлено ниже, потому что след довольно длинный).

Разрешение

Проблема заключается в том, что вы вводите точку решения в свой предикат skaiciavimai/3: действительно, если первый аргумент является список по крайней мере с одним элементом (вида [_|_]), Среда пролога может выбрать как второе, так и третье предложение: после того, как она успешно попробовала предложение skaiciavimai([First|Tail], S2, [First|Rest]), она также может стремиться выбрать следующее предложение skaiciavimai([_|Tail], S2, Rest). Так как нет предиката, который мешает этому выбору быть успешным, он также найдет решение, опуская элемент head. Вы можете решить эту проблему, добавив дополнительное ограничение в последнем предложении:

skaiciavimai([],_,[]).
skaiciavimai([First|Tail], S2, [First|Rest]) :-
    member(First, S2),
    skaiciavimai(Tail, S2, Rest).
skaiciavimai([First|Tail], S2, Rest) :-
    \+ member(First,S2),
    skaiciavimai(Tail, S2, Rest).

The \+ означает что-то вроде логическое не (хотя нужно быть осторожным, потому что не является проблемной темой влогическом программировании ). Итак, теперь мы препятствуем прологу выбрать третье предложение, которое успешно дано First является членом S2. При использовании этого кода результатом запроса будет:

?- bendri([a,b,c,d],[d,b,e],R).
R = [b, d] ;
false.

Таким образом, мы изменили определение skaiciavimai/3 теперь оно читается примерно так:: "C это список всех элементов, которые встречаются в A, которые также встречаются в B." поскольку для того, чтобы опустить элемент из A (третье предложение), он не должен быть членом B.

К лучшему предикату

В прологе цель состоит в том, чтобы сделать предикатразнонаправленным . Действительно, Вы хотите иметь возможность вызывать предикаты в разных направлениях. bendri/3 может быть реализовано таким образом, что bendri(A,B,[a,c]) также возвращает A = [a, c], B = [a, c] ; и т. д. (что и имеет место в данном случае). При проектировании предикатов необходимо учитывать многократное использование предиката.

След

?- trace.
true.

[trace]  ?- bendri([a,b,c,d],[d,b,e],R).
   Call: (6) bendri([a, b, c, d], [d, b, e], _G360) ? creep
   Call: (7) skaiciavimai([a, b, c, d], [d, b, e], _G360) ? creep
   Call: (8) lists:member(a, [d, b, e]) ? creep
   Fail: (8) lists:member(a, [d, b, e]) ? creep
   Redo: (7) skaiciavimai([a, b, c, d], [d, b, e], _G360) ? creep
   Call: (8) skaiciavimai([b, c, d], [d, b, e], _G360) ? creep
   Call: (9) lists:member(b, [d, b, e]) ? creep
   Exit: (9) lists:member(b, [d, b, e]) ? creep
   Call: (9) skaiciavimai([c, d], [d, b, e], _G448) ? creep
   Call: (10) lists:member(c, [d, b, e]) ? creep
   Fail: (10) lists:member(c, [d, b, e]) ? creep
   Redo: (9) skaiciavimai([c, d], [d, b, e], _G448) ? creep
   Call: (10) skaiciavimai([d], [d, b, e], _G448) ? creep
   Call: (11) lists:member(d, [d, b, e]) ? creep
   Exit: (11) lists:member(d, [d, b, e]) ? creep
   Call: (11) skaiciavimai([], [d, b, e], _G451) ? creep
   Exit: (11) skaiciavimai([], [d, b, e], []) ? creep
   Exit: (10) skaiciavimai([d], [d, b, e], [d]) ? creep
   Exit: (9) skaiciavimai([c, d], [d, b, e], [d]) ? creep
   Exit: (8) skaiciavimai([b, c, d], [d, b, e], [b, d]) ? creep
   Exit: (7) skaiciavimai([a, b, c, d], [d, b, e], [b, d]) ? creep
   Exit: (6) bendri([a, b, c, d], [d, b, e], [b, d]) ? creep
R = [b, d] ;
   Redo: (11) lists:member(d, [d, b, e]) ? creep
   Fail: (11) lists:member(d, [d, b, e]) ? creep
   Redo: (10) skaiciavimai([d], [d, b, e], _G448) ? creep
   Call: (11) skaiciavimai([], [d, b, e], _G448) ? creep
   Exit: (11) skaiciavimai([], [d, b, e], []) ? creep
   Exit: (10) skaiciavimai([d], [d, b, e], []) ? creep
   Exit: (9) skaiciavimai([c, d], [d, b, e], []) ? creep
   Exit: (8) skaiciavimai([b, c, d], [d, b, e], [b]) ? creep
   Exit: (7) skaiciavimai([a, b, c, d], [d, b, e], [b]) ? creep
   Exit: (6) bendri([a, b, c, d], [d, b, e], [b]) ? creep
R = [b] ;

Этот ответ следует за ответом @gusbro... Почему бы не сохранить логическую чистоту? Это же просто!

Просто замените третье предложение следующим:

skaiciavimai([First|Tail], S2, Rest) :-
   non_member(First, S2),
   skaiciavimai(Tail, S2, Rest).

И определить non_member/2 следующим образом:

non_member(X, Es) :-
   maplist(dif(X), Es).

Это продолжение этого логически чистого ответа, представленного ранее.

:- use_module(library(lambda)).

bendri(Es, Fs, Xs) :-
%          ^^
%          ||
%          |+----------------+\
%          ||                ||
%          vv                vv
   tfilter(Fs+\E^memberd_t(E,Fs), Es, Xs).
%            ^^
%            || 
%            \+------------------ Fs has global scope

Пример запроса, заданного OP:

?- bendri([a,b,c,d], [d,b,e], Xs).
Xs = [b,d].