Prolog 打印列表中的元素,但以不同方式处理最后一个元素

Prolog 打印列表中的元素,但以不同方式处理最后一个元素,prolog,Prolog,我编写了一个谓词,它打印出列表中除最后一个元素之外的每个元素。最后一个要素应以不同方式处理;它应该最后打印取而代之。这就是我所拥有的 write_data([]). write_data([X]) :- !, write('LAST!'), nl. write_data([X | Rest]) :- write(x), nl, write_data(Rest). 有更好的办法吗?有没有办法在没有剪切的情况下执行此操作?您可以通过使用至少包含两个元素的列表执行统一来避免剪

我编写了一个谓词,它打印出列表中除最后一个元素之外的每个元素。最后一个要素应以不同方式处理;它应该最后打印
取而代之。这就是我所拥有的

write_data([]).
write_data([X]) :-
    !, write('LAST!'), nl.
write_data([X | Rest]) :-
    write(x), nl,
    write_data(Rest).

有更好的办法吗?有没有办法在没有剪切的情况下执行此操作?

您可以通过使用至少包含两个元素的列表执行统一来避免剪切,例如:

write_data([]).
write_data([_]) :-
    write('LAST!'),
    nl.
write_data([X|Rest]) :-
    Rest = [_|_],
    write(X), nl,
    write_data(Rest).

提供对列表最后一个元素的访问的
last/2
谓词的常见定义是:

last([Head| Tail], Last) :-
    last(Tail, Head, Last).

last([], Last, Last).
last([Head| Tail], _, Last) :-
    last(Tail, Head, Last).

当使用绑定到封闭列表的第一个参数调用时,辅助谓词
last/3
,避免了假定Prolog系统实现第一个参数索引的虚假选择点。您可以修改此谓词以执行所需操作吗?

删除剪切的一般经验法则是,注意包含剪切的子句中的
true
,然后确保其他子句中的
false

因此:

write_data([]).

write_data([X]) :-
    /*!,*/write('LAST!'), nl.

write_data([X | Rest]) :-
    dif(Rest,[]) , /**/
    write(x), nl,
    write_data(Rest).

另一种确保列表至少包含两个元素的方法:
write_data([X1,X2 | Rest]):-…
@Flux:是的,但是您必须在递归中“重新打包”列表,这不是很有效。什么是“解包”?你的第一个解决方案似乎是最好的。奇怪的是,有些工作是在入口predikat中完成的,称为recursiv predikat;最好在recursiv predikat中完成所有工作。@Kintalken:a
[H | T]
是一个函子,为了访问参数(
H
T
),它需要一些工作。在第一个示例中,“每次迭代”的解包次数更多(通常列表中的每个项目需要3次解包),而在后一个示例中,列表中的每个项目只有一次解包。在Prolog库中,经常会看到这种谓词,使它的解包工作更少。此外,大多数prolog解释器对第一个参数进行了一些优化,从而使其更快地匹配
[]
,而不是
[| |]
。当然,从概念上讲,您所说的是正确的,支持列表的树结构中存在递归下降,但是!作为一个实用的问题,编译器会做一些效率更高的事情,因此
[H | T]
变得(几乎)像C结构,变量(通常)以数字作为插槽进行索引。例如
write_data([]).

write_data([X]) :-
    /*!,*/write('LAST!'), nl.

write_data([X | Rest]) :-
    dif(Rest,[]) , /**/
    write(x), nl,
    write_data(Rest).