查找给定元素的第n次出现

时间:2013-11-18 23:01:54

标签: prolog

我刚开始使用Prolog并遇到问题:

  

(a)给定列表L,对象X和正整数K,它返回   如果X出现至少K,则在L中出现第K次X的位置   在L中的时间,否则为0.

     

目标pos([a,b,c,b],b,2,Z)应该成功回答Z = 4

到目前为止,我有:

pos1([],H,K,F).
pos1([H],H,1,F).
pos1([H|T],H,K,F):- NewK is K - 1, pos1(T,H,NewK,F), F is F + 1.
pos1([H|T],X,K,F):- pos1(T,X,K,F).

但我无法弄明白为什么我会这样:

ERROR: is/2: Arguments are not sufficiently instantiated

非常感谢任何帮助!

4 个答案:

答案 0 :(得分:1)

使用

:- use_module(library(clpfd)).

我们根据(#>)/2(#=)/2if_/3dif/3(#<)/3定义pos/4

pos(Xs,E,K,P) :-
   K #> 0,
   pos_aux(Xs,E,K,1,P).

pos_aux([X|Xs],E,K,P0,P) :-
   P0+1 #= P1,
   if_(dif(X,E),
       pos_aux(Xs,E,K,P1,P),
       if_(K #< 2,
           P0 = P,
           (K0+1 #= K,
            pos_aux(Xs,E,K0,P1,P)))).

OP给出的示例查询:

?- X = b, N = 2, pos([a,b,c,b],X,N,P).
X = b, N = 2, P = 4.                     % succeeds deterministically

以下更一般的查询怎么样?

?- pos([a,b,c,b],X,N,P).
  X = a, N = 1, P = 1
; X = b, N = 1, P = 2
; X = b, N = 2, P = 4                    % (exactly like in above query)
; X = c, N = 1, P = 3
; false.

答案 1 :(得分:0)

让我们采用高级方法,交换结果代码的效率,以便于开发:

pos(L,X,K,P):-
   numerate(L,X,LN,1),  %// [A1,A2,A3...] -> [A1-1,A2-2,A3-3...], where Ai = X.
   ( drop1(K,LN,[X-P|_]) -> true ; P=0 ).

现在我们只实现两个新的谓词。 drop1(K,L,L2) 会从K-1中删除L个元素,因此我们会留下L2

drop1(K,L2,L2):- K<2, !.
drop1(K,[_|T],L2):- K1 is K-1, drop1(K1,T,L2).

numerate(L,X,LN,I) I的每个元素添加基于L的索引,但仅保留X s:

numerate([],_,[],_).
numerate([A|B],X,R,I):- I1 is I+1, ( A=X -> R=[A-I|C] ; R=C ), numerate(B,X,C,I1).

测试:

5 ?- numerate([1,b,2,b],b,R,1).
R = [b-2, b-4].

6 ?- pos([1,b,2,b],b,2,P).
P = 4.

7 ?- pos([1,b,2,b],b,3,P).
P = 0.

答案 2 :(得分:0)

我已经更正了你的代码而没有改变逻辑,这似乎已经很简单了。 刚刚添加了一个“顶级”处理程序,传递给实际工作者pos1 / 4并测试是否有效,否则返回0 - 在Prolog中有争议的方式,imo最好允许失败,我希望你会欣赏如何采用这个(见注释) )简化了你的代码...

pos(L,X,K,F):- pos1(L,X,K,F) -> true ; F=0.

% pos1([],H,K,F). useless: let it fail
% pos1([H],H,1,F). useless: already handled immediatly bottom
pos1([H|T],H,K,P):- K==1 -> P=1 ; NewK is K - 1, pos1(T,H,NewK,F), P is F + 1.
pos1([_|T],X,K,P):- pos1(T,X,K,F),P is F+1.

我希望您可以使用if / then / else结构。无论如何,收益率

7 ?- pos([a,b,c,b],b,2,Z).
Z = 4.

8 ?- pos([a,b,c,b],b,3,Z).
Z = 0.

答案 3 :(得分:0)

像这样的东西。外部谓词(这个强制执行指定的约束)调用内部工作者谓词:

kth( L , X , K , P ) :-
  is_list( L ) ,            % constraint: L must be a list
  nonvar(X) ,               % constriant: X must be an object
  integer(K) , K > 0        % constraint: K must be a positive integer
  kth( Ls , X , K , 1 , P ) % invoke the worker predicate with its accumulator seeded to 1
  .                         % easy!

is_list/2确保您有一个列表:

is_list(X) :- var(X) , !, fail .
is_list([]).
is_list([_|_]).

完成所有工作的谓词就是这个:

kth( []     , _ , _ , _ , 0 ) .      % if we hit the end of the list, P is 0.
kth( [X|Ls] , X , K , K , K ) :- ! . % if we find the Kth desired element, succeed (and cut: we won't find another Kth element)
kth( [_|Ls] , X , K , N , P ) :-     % otherwise
  N < K ,                            % - if we haven't got to K yet ...
  N1 is N+1 ,                        % - increment our accumulator , and
  kth(Ls,X,K,N1,P)                   % - recurse down.
  .                                  % easy!

虽然回答0而不是失败的概念不是Prolog Way,如果你问我。