Prolog - 查找列表中的相邻元素

时间:2016-02-27 07:45:05

标签: list recursion prolog traversal

我正在尝试定义一个谓词<asp:TextBox runat="server" Text='<%# Bind("qty")%>'/> ,如果X和Y在列表中相邻,则为真。我的代码目前是这样的:

adjacent(X, Y, Zs)

它适用于adjacent(_, _, []). adjacent(X, Y, [X, Y|Tail]) :- adjacent(X,Y, Tail). 的基本情况,但由于基本情况,每个其他情况也会返回true,我仍然坚持这一点。

另一个问题是,如果X不等于列表头部的第一部分,那么它会跳过X和Y并转到下一个'X';例如,如果 c 不等于 a ,那么它会跳过 a b 并检查是否 c 等于 c 。例如,当列表是

时,这是有问题的
adjacent(c, d, [a, b, c, d, e])

因为它最终永远不会检查 c (我相信)。

我很沮丧如何调和这两个问题,并将我对逻辑中的理解转化为代码。

编辑:感谢Christian Hujer的回答,我的基本案例错误已得到纠正,所以现在我只是坚持第二个问题。

5 个答案:

答案 0 :(得分:14)

在原始解决方案尝试中:

adjacent(_, _, []).
adjacent(X, Y, [X, Y|Tail]) :-
    adjacent(X,Y, Tail).

正如@ChristianHujer所指出的那样,第一个条款不应该存在,因为它不是真的。空列表应该没有相邻的元素。

第二个条款也存在问题。它表明XY在列表中相邻,但随后递归并且不仅仅是成功。适当的条款应该是:

adjacent(X, Y, [X,Y|_]).

如果它们是列表中的前两个元素,那么XY在列表中是相邻的,无论尾部是什么。这也形成了一个合适的基础案例。然后你的一般递归条款应该处理其余的情况:

adjacent(X, Y, [_|Tail]) :-
    adjacent(X, Y, Tail).

这表示XY[_|Tail]中相邻,如果它们在Tail中相邻。这样可以解决您遇到的第二个问题。

因此,整个解决方案将是:

adjacent(X, Y, [X,Y|_]).
adjacent(X, Y, [_|Tail]) :-
    adjacent(X, Y, Tail).

这将成功,XY按顺序一起出现在列表中。

<小时/> 这也可以通过DCG自然解决(尽管基于@ repeat append/3的解决方案更简洁):

adjacent(X, Y) --> ..., [X, Y], ... .
... --> [] | [_], ... .

adjacent(X, Y, L) :- phrase(adjacent(X, Y), L).
| ?- adjacent(b, c, [a,b,c,d]).

true ? a

(1 ms) no
| ?- 

答案 1 :(得分:7)

我认为你的基本情况是错误的。在您的情况下,您希望递归以假谓词终止,而不是使用真正的谓词。这是合乎逻辑的:在一个空列表中,没有相邻的元素。从不。

答案 2 :(得分:6)

在这个答案中,我们试图通过构建append/3

来保持简单
adjacent(E0, E1, Es) :-
    append(_, [E0,E1|_], Es).

示例查询:

?- adjacent(X, Y, [a,b,c,d,e]).
X = a, Y = b ;
X = b, Y = c ;
X = c, Y = d ;
X = d, Y = e ;
false.

答案 3 :(得分:6)

辅助谓词adjacent_/5总是“落后”恰好两个(列表项):

adjacent(X0, X1, [E0,E1|Es]) :-
   adjacent_(Es, E0, E1, X0, X1).

adjacent_([],      E0, E1, E0, E1).
adjacent_([E2|Es], E0, E1, X0, X1) :-
   if_(E0+E1 = X0+X1,
       true,
       adjacent_(Es, E1, E2, X0, X1)).

使用SWI-Prolog我们运行:

?- set_prolog_flag(double_quotes, chars).
true.

?- adjacent(a, b, "abab").
true.

?- adjacent(b, c, "abcd").
true. 

?- adjacent(X, Y, "abcd").
   X = a, Y = b
;  X = b, Y = c
;  X = c, Y = d.

修改

adjacent_/5的更正定义也为以下查询提供了正确的答案:

?- adjacent(X, X, [A,B,C]).
   X = A, A = B
;  X = B, B = C, dif(f(C,C),f(A,A)).

?- adjacent(a, X, "aab").
   X = a
;  X = b.

?- adjacent(a, b, "aab").
true.

答案 4 :(得分:4)

我认为这个定义在长期内比@ repeat的解决方案更可取:

adjacent(X0, X1, [E0,E1|Es]) :-
   adjacent_(Es, E0, E1, X0, X1).

adjacent_([],      E0, E1, E0, E1).
adjacent_([E2|Es], E0, E1, X0, X1) :-
   if_(( E0 = X0, E1 = X1 ),
       true,
       adjacent_(Es, E1, E2, X0, X1)).

使用具体化的:

','(A_1, B_1, T) :-
   if_(A_1, call(B_1, T), T = false).

;(A_1, B_1, T) :-
   if_(A_1, T = true, call(B_1, T)).