TL;DR:@CAFEBABE、@CapelliC、@mat和@sharky 的答案都达不到要求!
那么......之前提出的答案的缺点到底是什么?
@CAFEBABE 说:
这个解决方案的好处是运行时间在两个列表的长度上是线性的。
让我们来测试一下这个说法!
?- numlist(1,1000,Zs), time(posAt__CAFEBABE1(Zs,1000,Zs))。
% 999,001推理,0.090 CPU 在 0.091 秒内(100% CPU,11066910 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 4 次推理,0.000 秒内 0.000 CPU(97% CPU,66738 唇)
错误的。
无赖!其他人做得很好:
?- numlist(1,1000,Zs), time(posAt__CapelliC1(Zs,1000,Zs))。
% 671推理,0.000 CPU 在 0.000 秒内(98% CPU,3492100 唇)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...]。
?- numlist(1,1000,Zs), time(posAt__mat1(Zs,1000,Zs))。
% 3,996 次推理,0.001 秒内 0.001 CPU(99% CPU,3619841 唇)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 5 次推断,0.000 CPU 在 0.000 秒内(89% CPU,154703 唇)
错误的。
?- numlist(1,1000,Zs), time(posAt__sharky1(Zs,1000,Zs))。
% 1,000 次推理,0.000 CPU 在 0.000 秒内(100% CPU,2627562 唇)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 4 次推理,0.000 CPU 在 0.000 秒内(82% CPU,97109 唇)
错误的。
@CapelliC used nth1/3
,它可以(并且确实)导致通用终止问题:
?-时间((posAt__CapelliC1(_,N,[a,b,c]), false))。
**循环**
哦!其他人都做得很好:
?-时间((posAt__CAFEBABE1(_,_,[a,b,c]), false))。
% 14 次推论,0.000 CPU 在 0.000 秒内(88% CPU,1098470 唇)
假的。
?-时间((posAt__mat1(_,_,[a,b,c]), false))。
% 2,364 次推理,0.001 秒内 0.001 CPU(100% CPU,2764075 唇)
假的。
?-时间((posAt__sharky1(_,_,[a,b,c]), false))。
% 6 次推理,0.000 秒内 0.000 CPU(89% CPU,207247 唇)
假的。
@mat 的代码存在复杂性问题。@CAFEBABE 和 @CapelliC 做得“好一点” ——它们的代码更快,因为它们使用依赖于较低级别的原语(is)/2
和nth1/3
.
?- numlist(1,1000,Zs), time((posAt__mat1(Zs,_,_), false))。
% 33,365,972推理,1.643 CPU 在 1.643 秒内(100% CPU,20304661 嘴唇)
错误的。
?- numlist(1,1000,Zs), time((posAt__CAFEBABE1(Zs,_,_), false))。
% 1,001,002次推断,0.083 秒内 0.083 CPU(100% CPU,12006557 唇)
错误的。
?- numlist(1,1000,Zs), time((posAt__CapelliC1(Zs,_,_), false))。
% 171,673推理,0.030 CPU 在 0.030 秒内(100% CPU,5810159 唇)
错误的。
@sharky 的代码在这方面显然是最好的:
?- numlist(1,1000,Zs), time((posAt__sharky1(Zs,_,_), false))。
% 1,003次推理,0.001 秒内 0.001 CPU(100% CPU,1605658 唇)
错误的。
@sharky 的代码使用元逻辑内置谓词(==)/2
,当与未充分实例化的术语一起使用时,它会失去逻辑可靠性。此查询应该成功:
?- posAt__sharky1([a], 1, Xs)。
假的。
其他代码都给出了合乎逻辑的答案:
?- posAt__CAFEBABE1([a], 1, Xs)。
Xs = [a|_G235] ;
错误的。
?- posAt__CapelliC1([a], 1, Xs)。
Xs = [a|_G235]。
?- posAt__mat1([a], 1, Xs)。
Xs = [a|_G235] ;
错误的。
超越第一个答案,@CAFEBABE 的代码变得有点效率低下:
?- numlist(1,1000,Zs), time(posAt__CAFEBABE1(Zs,1,Zs))。
% 0 推理,0.000 CPU 在 0.000 秒内(93% CPU,0 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 999,004 次推理,0.076 秒内 0.076 CPU(100% CPU,13121058 唇)
错误的。
@sharky 的代码显示了类似的问题——但要小一个数量级:
?- numlist(1,1000,Zs), time(posAt__sharky1(Zs,1,Zs))。
% 1 推理,0.000 CPU 在 0.000 秒内(75% CPU,31492 唇)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 1,003次推理,0.001 秒内 0.001 CPU(100% CPU,1078556 唇)
错误的。
@CapelliC 和 @mat 的代码都很好:
?- numlist(1,1000,Zs), time(posAt__CapelliC1(Zs,1,Zs))。
% 7次推断,0.000 CPU 在 0.000 秒内(85% CPU,306802 唇)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...]。
?- numlist(1,1000,Zs), time(posAt__mat1(Zs,1,Zs))。
% 0 次推断,0.000 CPU 在 0.000 秒内(80% CPU,0 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 5次推断,0.000 秒内 0.000 CPU(84% CPU,345662 唇)
错误的。
那么我们该怎么办?为什么不遵循这种方法并结合@mat 和@sharky 的代码呢?
:- 使用模块(库(clpfd))。
posAt__NEW(L0, Pos, L1) :-
posAt__NEW_(L0, 1, Pos, L1)。
posAt__NEW_([ X |_], Pos, Pos, [ X |_])。
posAt__NEW_([_|X0s], CurrPos, Pos, [_|X1s]) :-
CurrPos #< Pos,
NextPos #= CurrPos + 1,
posAt__NEW_(X0s, NextPos, Pos, X1s)。
让我们重新运行上面的示例查询posAt__NEW/3
:
?- numlist(1,1000,Zs), time(posAt__NEW(Zs,1000,Zs))。
% 4,997 次推理,0.000 CPU 在 0.000 秒内(100% CPU,18141619 唇)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 9 次推理,0.000 CPU 在 0.000 秒内(71% CPU,122877 唇)
错误的。
?-时间((posAt__NEW(_,_,[a,b,c]), false))。
% 440 次推理,0.001 秒内 0.001 CPU(98% CPU,803836 唇)
假的。
?- numlist(1,1000,Zs), time((posAt__NEW(Zs,_,_), false))。
% 154,955 次推理,0.014 秒内 0.014 CPU(100% CPU,11067900 唇)
错误的。
?- posAt__NEW([a], 1, Xs)。
Xs = [a|_G229] ;
错误的。
?- numlist(1,1000,Zs), time(posAt__NEW(Zs,1,Zs))。
% 1 推理,0.000 CPU 在 0.000 秒内(93% CPU,121818 唇)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 7次推断,0.000 秒内 0.000 CPU(86% CPU,266748 唇)
错误的。
好吧!最后,我们确保上面第三个查询中使用的目标具有线性复杂度:
?- numlist(1,100,Zs), time((posAt__NEW(Zs,_,_), false))。
% 15,455 次推断,0.004 秒内 0.004 CPU(100% CPU,3545396 唇)
错误的。
?- numlist(1,1000,Zs), time((posAt__NEW(Zs,_,_), false))。
% 154,955 次推理,0.016 CPU 在 0.017 秒内(98% CPU,9456629 唇)
错误的。
?- numlist(1,10000,Zs), time((posAt__NEW(Zs,_,_), false))。
% 1,549,955推理,0.098 CPU 在 0.099 秒内(99% CPU,15790369 唇)
错误的。
?- numlist(1,100000,Zs), time((posAt__NEW(Zs,_,_), false))。
% 15,499,955 次推理,1.003 个 CPU 在 1.007 秒内(100% CPU,15446075 个嘴唇)
错误的。