Prolog两个列表交集 - 为什么要继续检查?

时间:2015-12-03 15:03:31

标签: prolog

我需要找到列表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 个答案:

答案 0 :(得分:3)

你的问题是即使第二个子句成功,skaiciavimai([First|Tail], S2, Rest) :- \+ (member(First, S2)), skaiciavimai(Tail, S2, Rest). 的第三个子句也会成功回溯。如果第二个子句成功,我想你想跳过第三个句子。

为此,您可以在第三个子句中添加一个检查:

S2

如果在For Each element In Worksheets("SQLresults").Range("B") 中找到第一个列表的头部,则第三个子句失败。

答案 1 :(得分:2)

简单的故事:;表示Prolog应该寻找替代方案,并且由于bendri(A,B,C)被定义为C a 元素列表发生在AB(根据您的定义),它将打印所有可能的结果。您可以在下面的trace上看到这一点(下面添加,因为跟踪相当长)。

分辨率

问题是你在skaiciavimai/3谓词中引入了一个决策点:确实第一个参数是一个至少包含一个元素的列表(格式为[_|_]),Prolog环境可以选择第二个和第三个子句:在成功尝试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).

\+意味着像逻辑而不是(虽然必须小心,因为逻辑编程中不是一个有问题的话题)。所以现在我们阻止Prolog成功选择第三个子句,因为FirstS2的成员。使用此代码时,查询结果为:

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

我们因此更改了skaiciavimai/3的定义,现在它的内容如下所示:CAB中出现的所有元素的列表A同样。“因为为了省略B中的元素(第三个子句),它不应该是bendri/3的成员。

迈向更好的谓词

在Prolog中,目标是使谓词多向。实际上,您希望能够以不同的方向调用谓词。可以实现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] ; 等等(这种情况就是这种情况)。在设计谓词时,需要考虑谓词的多种用法。

微量

skaiciavimai/3

答案 2 :(得分:2)

这个答案跟随@ 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).

答案 3 :(得分:2)

这是前面提到的this logically-pure answer的后续行动。

:- 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].