如何在Prolog

时间:2015-05-26 16:51:40

标签: list prolog

我正在尝试编写Prolog代码,找到列表中的 n -th元素。 我编写了下面的代码,但它没有正确地返回元素。

match([Elem|Tail],Num,Num,Elem).
match([Elem|Tail],Num,C,MatchedNumber):-
   match(Tail,Num,N,Elem),
   C is N+1.

在第一行我说,如果请求的元素号等于counter,则将当前列表的第一个元素赋给名为MatchedNumber的变量。此代码返回NumCounter权限,但我不知道为什么当我想将MatchedNumber设置为Elem时,它始终返回列表的第一个元素

1:这段代码出了什么问题? 2:我怎么说而不是显示匹配的号码,将其从列表中删除?

2 个答案:

答案 0 :(得分:7)

首先,有一个内置nth0/3

?- nth0(0,[a,b,c],X).
X = a.

?- nth0(1,[a,b,c],X).
X = b.

?- nth0(2,[a,b,c],X).
X = c.

?- nth0(3,[a,b,c],X).
false.

获取 i -th元素

问题在于归纳案例:

match([Elem|Tail],Num,Counter,MatchedNumber):-
    match(Tail,Num,N,Elem),
    C is N+1.

Prolog对C一无所知,所以最后一句话不会强迫Prolog返回 i -th元素。它可以简单地返回任何元素,因为N将在递归调用中与Num匹配,然后将C设置为Num+1,但这不是问题,因为{{ 1}}不受任何约束。

解决此问题的更好方法是使用减量计数器:

C

示例

match([H|_],0,H) :-
    !.
match([_|T],N,H) :-
    N > 0, %add for loop prevention
    N1 is N-1,
    match(T,N1,H).

因此,基本情况是索引为?- match([a,b,c,d,e],0,X). X = a. ?- match([a,b,c,d,e],1,X). X = b. ?- match([a,b,c,d,e],2,X). X = c. ?- match([a,b,c,d,e],3,X). X = d. ?- match([a,b,c,d,e],4,X). X = e. ?- match([a,b,c,d,e],5,X). false. ,在这种情况下,您返回 head ,否则您将查询 i-1 -th元素尾巴这也是一种更具说明性的方法。

这种方法也使用尾递归,这通常会显着提升性能。

修改原始谓词

un-Prolog 使用迭代器绑定,通常使用反向迭代器。

但您可以按如下方式修改谓词:

0

所以有一些错误:

  • 使用&#34; cut&#34;第一个句子中的match([Elem|_],Num,Num,Elem) :- !. match([_|Tail],Num,Count,MatchedNumber) :- Count < Num, Count1 is Count+1, match(Tail,Num,Count1,MatchedNumber). :因为如果匹配,我们知道Prolog不应该尝试第二个;
  • 在递归调用中使用!而不是MatchedNumber;
  • 执行绑定检查Elem
  • 在进行递归调用之前执行计数器Count < Num的增量;和
  • 用下划线Count1 is Count+1替换所有不使用的变量。

然后是一个例子:

_

但如前所述,传递额外的参数等是无效的。

从列表

中删除 i -th元素

可以使用几乎等效的方法从列表中删除 i -th元素:

?- match([a,b,c,d,e],0,0,X).
X = a.

?- match([a,b,c,d,e],1,0,X).
X = b.

?- match([a,b,c,d,e],2,0,X).
X = c.

?- match([a,b,c,d,e],3,0,X).
X = d.

?- match([a,b,c,d,e],4,0,X).
X = e.

?- match([a,b,c,d,e],5,0,X).
false.

这里的基本情况再次是索引是removei([],_,[]). removei([_|T],0,T) :- !. removei([H|T],N,[H|TR]) :- N1 is N-1, removei(T,N1,TR). ,在这种情况下,列表的尾部被删除(因此丢弃了头部)。归纳案例将列表的头部放在结果列表的头部,并依靠递归调用从尾部删除正确的项目。添加了另一个基本案例0,因为 i 可能大于列表的长度,在这种情况下,此谓词不会删除任何项目。

示例

removei([],_,[]).

答案 1 :(得分:4)

要查找列表的第n个元素(n相对于零),这样的事情应该足够了:

find_nth_element_of_list( 0 , X , [X|_]  ) .
find_nth_element_of_list( N , X , [_|Xs] ) :-
  N > 0 ,
  N1 is N-1 ,
  find_nth_element_of_list( N1 , X , Xs )
  .

同样,要删除列表的第n个元素,这样的事情就足够了:

remove_nth_element_of_list( 0 , [_|Xs] , Xs ) .      % at n=0, toss the head and unify the tail with the result set
remove_nth_element_of_list( N , [X|Xs] , [X|Ys] ) :- % at n>0, prepend the head to the result and recurse down.
  N > 0 ,
  N1 is N-1 ,
  remove_nth_element_of_list( N1 , Xs , Ys )
  .