【发布时间】:2019-01-28 19:41:35
【问题描述】:
我们想检查一个元素是否出现在列表的最后,我们有这个 prolog 程序,这对我来说很明显:
last(X,[X]).
last(X,[_|L]):-
last(X,L).
但是我们的老师给了我们另一个解决方案,他说它更优化,有它:
last(X,[X]).
last(X,[_,Y|L]):-
last(X,[Y|L]).
为什么第二种解决方案更优化?
【问题讨论】:
标签: prolog
我们想检查一个元素是否出现在列表的最后,我们有这个 prolog 程序,这对我来说很明显:
last(X,[X]).
last(X,[_|L]):-
last(X,L).
但是我们的老师给了我们另一个解决方案,他说它更优化,有它:
last(X,[X]).
last(X,[_,Y|L]):-
last(X,[Y|L]).
为什么第二种解决方案更优化?
【问题讨论】:
标签: prolog
这完全取决于您测量的内容。显然,您的老师做了@Armatorix 在他的回答中所做的事情,并且只是计算了 last/2 的调用。但在实践中,您的教师版本可能在所有 Prolog 系统上都会变慢,甚至明显变慢:
% Simple version:
?- length(Xs,10000000), time(last(X,Xs)).
% 10,000,000 inferences, 0.852 CPU in 0.852 seconds (100% CPU, 11735202 Lips)
% "Optimized" version
?- length(Xs,10000000), time(last(X,Xs)).
% 9,999,999 inferences, 4.436 CPU in 4.437 seconds (100% CPU, 2254074 Lips)
要了解原因,您必须意识到“优化”版本是语法糖
last(X,[X]).
last(X,[_,Y|L]):-
YL = [Y|L], % this takes time!
last(X,YL).
【讨论】:
好吧,理论上他是对的。
使用他的方法,我们不会检查总是包含在列表中的最后一个空元素。
用 2 个东西很容易检查,第一个是 time 函数,另一个是 trace。以下是列表(lastX 是您的教师版本,lastY 是您的版本):
?- time(lastY(5,[1,2,3,4,5])).
% 5 inferences, 0.000 CPU in 0.000 seconds (86% CPU, 1743983 Lips)
true
?- time(lastX(5,[1,2,3,4,5])).
% 4 inferences, 0.000 CPU in 0.000 seconds (86% CPU, 194203 Lips)
true .
?- time(lastX(6,[1,2,3,4,5])).
% 6 inferences, 0.000 CPU in 0.000 seconds (87% CPU, 279382 Lips)
false.
?- time(lastY(6,[1,2,3,4,5])).
% 7 inferences, 0.000 CPU in 0.000 seconds (85% CPU, 335008 Lips)
false.
[trace] ?- lastY(6,[1,2,3,4,5]).
Call: (7) lastY(6, [1, 2, 3, 4, 5]) ? Unknown option (h for help)
Call: (7) lastY(6, [1, 2, 3, 4, 5]) ? creep
Call: (8) lastY(6, [2, 3, 4, 5]) ? creep
Call: (9) lastY(6, [3, 4, 5]) ? creep
Call: (10) lastY(6, [4, 5]) ? creep
Call: (11) lastY(6, [5]) ? creep
Call: (12) lastY(6, []) ? creep
Fail: (12) lastY(6, []) ? creep
Fail: (11) lastY(6, [5]) ? creep
Fail: (10) lastY(6, [4, 5]) ? creep
Fail: (9) lastY(6, [3, 4, 5]) ? creep
Fail: (8) lastY(6, [2, 3, 4, 5]) ? creep
Fail: (7) lastY(6, [1, 2, 3, 4, 5]) ? creep
false.
[trace] ?- lastX(6,[1,2,3,4,5]).
Call: (7) lastX(6, [1, 2, 3, 4, 5]) ? creep
Call: (8) lastX(6, [2, 3, 4, 5]) ? creep
Call: (9) lastX(6, [3, 4, 5]) ? creep
Call: (10) lastX(6, [4, 5]) ? creep
Call: (11) lastX(6, [5]) ? creep
Fail: (11) lastX(6, [5]) ? creep
Fail: (10) lastX(6, [4, 5]) ? creep
Fail: (9) lastX(6, [3, 4, 5]) ? creep
Fail: (8) lastX(6, [2, 3, 4, 5]) ? creep
Fail: (7) lastX(6, [1, 2, 3, 4, 5]) ? creep
false.
【讨论】:
lastY 版本,有一个空列表的调用,而lastX 没有这样的调用。我认为线索是找出当只有一个元素时调用哪个谓词,是具有一个参数的谓词,还是具有递归性的谓词。