Prolog:检查某些内容是否是列表中的最后一项?

时间:2014-02-11 06:15:37

标签: list prolog dcg

我是prolog的新手,我基本上试图写一个如果给定项目是给定列表中的最后一项,则评估为true的子句。这就是我所拥有的:

last(X,[Y|X]).
last(X,[Y|Z]) :- last(X,Z).

我认为这可以解决问题,但是当我问prolog时:

?- last(c,[a,b,c]).

Prolog返回false。我尝试了以下查询,看看Prolog认为应该符合我对last的定义:

?- last(c,X).
X = [_G530|c] ;
X = [_G530, _G533|c] ;
X = [_G530, _G533, _G536|c]

所以,我不确定的是为什么“|”符号仍然在列表中?

更新:last([c],[a,b,c])产生所需的行为。但是,我不确定为什么我的第一个论点必须是一个列表?

4 个答案:

答案 0 :(得分:7)

你可能想要这个:

 last(X,[X]).
 last(X,[_|Z]) :- last(X,Z).

|表示“尾巴”或“列表的其余部分”。

使用?- last(c,X). Prolog生成列表(根据您的第一个定义),其中c为最后一项。

当您查询?- last(c,[a,b,c]).时,它会返回false,因为您没有为只有一个项目[X][X|[]]的列表定义案例。因此,当列表短于两个项目时,它会失败。

但是,last([c],[a,b,c])成功,因为你得到[b|_29]或任何表示尾部可能是任何列表的东西。所以'_29'可以是'[c]',满足第一个定义,如last([c],[b|[c]]).请记住,Prolog中的非空列表实际上是第一个列表项(头)和其余列表(尾部) )。通常写为[head | tail]。

答案 1 :(得分:3)

为什么不从语法角度来看待事物。那么列表中的最后一个元素是什么?

last(X, Xs) :-
   phrase( ( ..., [X] ), Xs).

... --> [] | [_], ... . % any sequence

答案 2 :(得分:2)

为什么不只使用附加?

last(X,Y) :-
    append(_,[X],Y).

http://www.swi-prolog.org/pldoc/man?predicate=append/3

答案 3 :(得分:1)

因为列表的尾部本身就是一个列表。

Prolog中的列表可以看作是[H | T],其中H是第一个元素(头部),而T(尾部)是列表所有其他元素。

当你分解它时,你的列表[a, b, c]实际上是[a | [b | [c | [] ] ] ](最后一个尾部总是一个空列表):

List: [a, b, c]   Head: a   Tail: [b, c]
List: [b, c]      Head: b   Tail: [c]
List: [c]         Head: c   Tail: []

所以当你到达问题是last(c, [b, c])时,它会分解为last(c, [b|[c]]),这就是第一个子句无法实例化的原因,因为X可以不是c[c]。这就是为什么当你问last([c],[a,b,c]) 的工作原因。

version proposed by alpha有效,因为它考虑了这一点:

% A list ends with an element if contains exactly that element.
last(X,[X]).

% A list ends with an element if its tail ends with that element.
% (Since we don't care about the head, we use an underscore).
last(X,[_|T]) :- last(X,T).