解析列表时生成可能的每个结果:元素(N,L,X)

时间:2016-06-16 15:48:46

标签: prolog

我正在尝试实现一个简单的元素(N,L,X)谓词,其中L是列表,X是列表的元素,N是列表中此元素的位置。
我希望能够做到这一点:

element(3, [a,b,c,d,e], X). 
yes : X=c.

element(N, [a,b,c,d,e], X).  
yes : { N=1, X=a}; { N=2, X=b}; ... { N=5, X=e};

我相信我已经在某个地方见过这个,但我无法找到它。 感谢。

1 个答案:

答案 0 :(得分:3)

由于您试图描述列表,该列表的潜在元素与其位置之间的关系,为什么不给出谓词是一个更具描述性的名称,例如list_element_position / 3。然后考虑关系应描述的内容。基本上有两种情况:

1)列表的头部与元素匹配。在这种情况下,您已经知道该元素的位置。但也可能有其他事件发生,所以:

2)无论头部是否与元素匹配,我们都应该查看列表的尾部,因为可能会有更多的事件发生。

累加器可用于计算位置。我从你的第一个例子中得到它,你想开始计算1。把所有这些放在一起你可以写出类似的东西:

list_element_position(L,E,P) :-
   list_element_position_(L,E,P,1).         % start counting at 1

list_element_position_([X|Xs],X,P,P).       % case 1)
list_element_position_([X|Xs],Y,R,P0) :-    % case 2)
   P1 is P0+1,
   list_element_position_(Xs,Y,R,P1).

您的示例查询:

   ?- list_element_position([a,b,c,d,e],E,3).
E = c ? ;
no
   ?- list_element_position([a,b,c,d,e],E,X).
E = a,
X = 1 ? ;
E = b,
X = 2 ? ;
E = c,
X = 3 ? ;
E = d,
X = 4 ? ;
E = e,
X = 5 ? ;
no

多次出现元素:

   ?- list_element_position([a,b,c,d,e,a],a,X).
X = 1 ? ;
X = 6 ? ;
no

如果你只打算在第一个参数被接地的情况下使用谓词,那么这已经可以了。但是,如果您想提出以下问题:某个位置有哪些列表,比如a,请说1?:

   ?- list_element_position(L,a,1).
L = [a|_A] ? ;

你得到一个答案然后谓词循环。你可以通过向list_element_position / 3添加一个长度为2的目标来避免这种情况:

list_element_position(L,E,P) :-
   length(L,_),                       % <- here
   list_element_position_(L,E,P,1).

上述查询现在可以产生其他解决方案:

   ?- list_element_position(L,a,1).
L = [a] ? ;
L = [a,_A] ? ;
L = [a,_A,_B] ? ;
L = [a,_A,_B,_C] ? ;
...

或者甚至更好,您可以通过使用clpfd并在list_element_position_ / 4中添加目标来避免循环,以确保累加器不会变得大于实际位置:

:- use_module(library(clpfd)).

list_element_position(L,E,P) :-
   list_element_position_(L,E,P,1).

list_element_position_([X|Xs],X,P,P).
list_element_position_([X|Xs],Y,R,P0) :-
   R #> P0,                                  % <- here
   P1 #= P0+1,
   list_element_position_(Xs,Y,R,P1).

这种方式查询产生单个解决方案并随后终止:

   ?- list_element_position(L,a,1).
L = [a|_A] ? ;
no