为什么SWI-Prolog文档会将append(_, [Last], List)
建议为可移植的last/2
而不是reverse(List, [Last|_])
(请参阅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.
答案 0 :(得分:2)
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。
答案 1 :(得分:1)
实际上,系统完全符合我期望的逆:
13 ?- length(L,1000000),time(reverse(L,[X|_])),statistics.
% 1,000,002 inferences, 0.422 CPU in 0.424 seconds (100% CPU, 2367605 Lips)
% Started at Tue Mar 10 14:31:08 2015
% 523.563 seconds cpu time for 7,770,847 inferences
% 13,661 atoms, 4,540 functors, 3,987 predicates, 81 modules, 214,610 VM-codes
%
% Limit Allocated In use
% Local stack: 268,435,456 12,288 1,904 Bytes
% Global stack: 268,435,456 100,659,184 72,011,904 Bytes
% Trail stack: 268,435,456 129,016 2,280 Bytes
%
% 8 garbage collections gained 1,837,408 bytes in 1.346 seconds.
% Stack shifts: 13 local, 68 global, 47 trail in 0.034 seconds
% 2 threads, 0 finished threads used 0.000 seconds
L = [_G1238, _G1241, _G1244, _G1247, _G1250, _G1253, _G1256, _G1259, _G1262|...].
14 ?- length(L,1000000),time(append(_,[X],L)),statistics.
% 999,999 inferences, 0.572 CPU in 0.574 seconds (100% CPU, 1747727 Lips)
% Started at Tue Mar 10 14:31:08 2015
% 536.544 seconds cpu time for 8,772,339 inferences
% 13,662 atoms, 4,540 functors, 3,987 predicates, 81 modules, 214,615 VM-codes
%
% Limit Allocated In use
% Local stack: 268,435,456 12,288 2,960 Bytes
% Global stack: 268,435,456 50,327,536 48,011,920 Bytes
% Trail stack: 268,435,456 30,712 2,312 Bytes
%
% 8 garbage collections gained 1,837,408 bytes in 1.346 seconds.
% Stack shifts: 13 local, 72 global, 50 trail in 0.036 seconds
% 2 threads, 0 finished threads used 0.000 seconds
L = [_G1240, _G1243, _G1246, _G1249, _G1252, _G1255, _G1258, _G1261, _G1264|...]
.
似乎reverse / 2正在使用append / 3分配的2倍。反向/ 2的全局和跟踪堆栈使用是双倍的,反向/ 2的结果是巧妙地编译为反向/ 4 ....