这里有更多方法可以做到这一点。
我不建议实际使用以下任何方法,但 IMO 它们很有趣,因为它们对其他代码和各个 Prolog 处理器提供的 Prolog 库给出了不同的看法:
在前三个变体中,我们将“递归部分”委托给内置/库谓词:
last_but_one_append(X,Es) :-
append(_, [X,_], Es).
:- use_module(library(lists)).
last_but_one_reverse(X, Es) :-
reverse(Es, [_,X|_]).
last_but_one_rev(X, Es) :-
rev(Es, [_,X|_]). % (SICStus only)
或者,我们可以使用香草自制的myappend/3 和myreverse/2:
myappend([], Bs, Bs).
myappend([A|As], Bs, [A|Cs]) :-
myappend(As, Bs, Cs).
last_but_one_myappend(X, Es) :-
myappend(_, [X,_], Es).
myreverse(Es, Fs) :-
same_length(Es, Fs), % for universal termination in mode (-,+)
myreverse_(Es, Fs, []).
myreverse_([], Fs, Fs).
myreverse_([E|Es], Fs, Fs0) :-
myreverse_(Es, Fs, [E|Fs0]).
last_but_one_myreverse(X, Es) :-
myreverse(Es, [_,X|_]).
让我们进行实验1!
bench_last :-
\+ ( length(Ls, 10000000),
member(M, [you,they,f1,f2,mat,dcg,dcgx,ap,
append,reverse,rev,
myappend,myreverse]),
write(M), write(' '),
atom_concat(last_but_one_,M,P),
\+ time(call(P,_L,Ls))
).
以下是使用 SICStus Prolog 和 SWI-Prolog3,4 的运行时2:
SICStus | SICStus | SWI |
4.3.2 | 4.3.
3 | 7.3.20 |
-------------------+----------+--------|
你0.26s | 0.10s | 0.83s |
3.1× 8.3×
他们0.27s | 0.12s | 1.03s |
3.8× 8.5×
f1 0.04s | 0.02s | 0.43s |
10.8× 21.5×
f2 0.02s | 0.02s | 0.37s |
18.5× 18.5×
垫0.26s | 0.11s | 1.02s |
3.9× 9.0×
dcg 1.06s | 0.77s | 1.47s |
1.3× 1.9×
dcgx 0.31s | 0.17s | 0.97s |
3.1× 5.7×
ap 0.23s | 0.11s | 0.42s |
1.8× 3.8×
追加 1.50s | 1.13s | 1.57s |
1.0× 1.3×
反向 0.36s | 0.32s | 1.02s |
2.8× 3.1×
转 0.04 秒 | 0.04s |
--"-- |
25.6× 25.6×
myappend 0.48s | 0.33s | 1.56s |
3.2× 4.7×
myreverse 0.27s | 0.26s | 1.11s |
4.1× 4.2×
编辑:添加了 SICStus Prolog 4.3.3 基准测试数据
非常令人印象深刻!在 SICStus/SWI 加速列中,> 10% 的差异得到粗体。
脚注 1:此答案中显示的所有测量值均在 Intel 上获得
Haswell处理器
Core i7-4700MQ。
脚注 2:rev/2 由 SICStus 提供,但不是由 SWI 提供。我们比较了最快的“反向”库谓词。
脚注 3:需要 SWI 命令行选项 -G1G 以防止出现 Out of global stack 错误。
脚注 4:此外,尝试了 SWI 命令行选项 -O(优化),但没有产生任何改进。