为什么这个“last_element”prolog谓词更优化?

时间:2017-10-10 11:09:55

标签: prolog

我们想检查一个元素是否出现在列表的最后一个,我们有这个prolog程序对我来说很明显:

last(X,[X]).
last(X,[_|L]):-
    last(X,L).

但我们的老师给了我们另一个解决方案,他说它更优化,有它:

last(X,[X]).
last(X,[_,Y|L]):-
    last(X,[Y|L]).

为什么第二种解决方案更优化?

2 个答案:

答案 0 :(得分:3)

这一切都取决于你衡量的是什么。显然你的老师会做@Armatorix在答案中所做的事情,并简单地计算最后/ 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).

答案 1 :(得分:2)

好的,理论上他是对的。 使用他的方法,我们不会检查列表中始终包含的最后一个空元素。 用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.