为什么 SWI-Prolog 文档建议将 append(_, [Last], List)
作为可移植的 last/2
而不是说 reverse(List ,[最后|_])
(参见here)? reverse/2
本身是否没有像 append/3
那样广泛实现?还是图片中还遗漏了其他内容?
无论哪种方式,如果列表是循环的,这三个都不会终止:
?- L = [z|L], last(L, Last).
^CAction (h for help) ? abort
% Execution Aborted
?- L = [z|L], append(_, [Last], L).
^CAction (h for help) ? abort
% Execution Aborted
?- L = [z|L], reverse(L, [Last|_]).
^CAction (h for help) ? abort
% Execution Aborted
但是,reverse/2
至少不会在正确的列表上留下选择点:
?- append(_, [Last], [a]).
Last = a ;
false.
?- reverse([a], [Last|_]).
Last = a.
最佳答案
reverse/2
的定义实际上不太常见,而且 SWI 的实现具有更好的终止行为,而许多其他实现仅在第一个参数是列表时才终止。我看到至少有 3 种不同的实现:一方面是 SWI,另一方面是 SICStus 和许多其他实现,然后是介于两者中间的 XSB。您可以通过以下目标来区分它们:
reverse(Xs, [a]). % terminates for SWI and XSB
reverse([a|Xs], [a]). % terminates for SWI
就性能而言,我希望传统的 reverse/2
(不是 SWI 的实现)应该更快一点,因为它的运行完全是确定性的。另一方面,它在堆上重新创建整个列表。
在当前的实现中,append(_, [L], Xs)
的实现并不理想:对于列表 Xs
的每个元素,都会创建一个选择点并然后删除,使最后一个选择点保持事件状态。
更多请参见this question .
关于prolog - 用 `last/2` 或 `append/3` 实现 `reverse/2`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28964538/