List 序言:检查列表中是否有最后一项?

List 序言:检查列表中是否有最后一项?,list,prolog,dcg,List,Prolog,Dcg,我不熟悉prolog,基本上是想写一个子句,如果给定的项是给定列表中的最后一项,那么这个子句的计算结果将为true。以下是我所拥有的: last(X,[Y|X]). last(X,[Y|Z]) :- last(X,Z). 我原以为这样就行了,但当我问序言: ?- last(c,[a,b,c]). Prolog返回false。我尝试了以下查询,以查看Prolog认为什么应该符合我对last的定义: ?- last(c,X). X = [_G530|c] ; X = [_G530, _G533|

我不熟悉prolog,基本上是想写一个子句,如果给定的项是给定列表中的最后一项,那么这个子句的计算结果将为true。以下是我所拥有的:

last(X,[Y|X]).
last(X,[Y|Z]) :- last(X,Z).
我原以为这样就行了,但当我问序言:

?- last(c,[a,b,c]).
Prolog返回false。我尝试了以下查询,以查看Prolog认为什么应该符合我对last的定义:

?- last(c,X).
X = [_G530|c] ;
X = [_G530, _G533|c] ;
X = [_G530, _G533, _G536|c]
所以,我不确定的是为什么“|”符号仍然在列表中

更新:最后([c]、[a、b、c])生成所需的行为。但是,我不确定为什么我的第一个参数必须是一个列表?

您可能需要:

 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|u 29]
或任何表示尾部可能是任何列表的内容。所以它的“_29”可以是“[c]”,满足第一个定义,如
last([c],[b|[c]])。
记住,Prolog中的非空列表实际上是第一个列表项(head)和其余列表项(tail)的一对。通常写为[头|尾]

因为列表的尾部是列表本身

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

分解列表时,您的列表实际上是
[a,b,c]
(最后一个尾部始终是一个空列表):

所以当你问
last(c[b,c])
时,它会分解为
last(c[b[c]])
,这就是为什么第一个子句不能被实例化,因为
X
不能同时是
c
[c]
。这就是为什么当你问最后一个([c],[a,b,c])时它确实起作用的原因

工程,因为它考虑到了这一点:

% 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).

为什么不从语法的角度看问题呢。那么,列表中的最后一个元素是什么

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

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

为什么不用append呢

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

避免单身的最佳方法:
last(X,Z]):-last(X,Z)。
True。特别是当警告可能会让初学者感到困惑时。我得到
2?-last(X[1,2,3])
X=3
错误。
。这是预期的吗?嗯。我预期它应该是确定性的,但现在我尝试了,如果不使用剪切-
last(X,[[u124; B]):-B=[[u124; B],!,最后一个(X,B)。
最后一个(X,[X]):-。这是出乎意料的。@williness:我们不要把逻辑决定论和具体的性能特性混淆起来。具有正如您所指出的,您正在为“性能”而牺牲逻辑完整性
last(X,[X | Xs])
应该可以成功地得到无限多的答案。@WillNess:巧妙地使用!也许有可能,但这是一场噩梦,绝对不值得付出努力。毕竟,只有一个选择是多余的。如果列表中的元素和ChoicePoint一样多,那就另当别论了。这确实是严重的。Prolog将递归规则放在最后的约定有时避免了这种情况。一个完美的实现是:它不使用任何切割,并避免了超级选择点。
last(X,Y) :-
    append(_,[X],Y).