与2个示例相关的参数没有充分实例化

问题描述 投票:3回答:3

这是一个非常常见的问题,但我想把它与两个在我眼中看起来非常相似的例子联系起来,而且还是一个正确而另一个没有。

正确的例子:

k_th_element(X,[X|_],1).
k_th_element(X,[_|L],K):- K>1,K1 is (K-1),k_th_element(X,L,K1).

错误的例子

length2(1,[_]).  
length2(X,[_|Ys]) :- X>1, X1 is (X-1), length(X1,Ys).

为什么prolog会对每个案件抱怨或不抱怨?

更新:我想我明白了。我无法理解的是,谓词是什么,但你如何称呼它并不重要。所以这是正确的:k_th_element(X,[1,2,3,4,5],3)因为你有一个K的值,它是“是”运算符的正确变量。但同时k_th_element(3,[1,2,3,4,5],Y)将不起作用,因为Y是一个变量,我们的“目标”,我们不能在右边“是“运营商。如我错了请纠正我。

list prolog clpfd
3个回答
3
投票

如同垫子所提出的,有一种更灵活的方式来实现相同的目标:

:- use_module(library(clpfd)).

length2(0,[]).  
length2(X,[_|Ys]) :- X#>0, X1#=X-1, length2(X1,Ys).

3
投票

首先,有参数顺序。对于length/2来说,它更像是length(List, Length)

对于给定列表和未知长度的情况,由于所有X1 #= X-1约束暗示了N约束变量,因此您的版本效率相对较低。版本length3/2有一个约束变量。 (它快了大约7倍。我仍然感到惊讶的是它并不比它快,也许有人可以帮助另一个答案?)

:- use_module(library(clpfd)).

length2([], 0).
length2([_E|Es], N0) :-
   N0 #> 0,
   N1 #= N0-1,
   length2(Es, N1).

length3(Es, N) :-
   length3(Es, 0, N).

length3([], N,N).
length3([_E|Es], N0,N) :-
   N1 is N0+1,
   N #>= N1,
   length3(Es, N1,N).

/*

?- length(L,1000), time(length2(L,N)).
% 783,606 inferences, 0.336 CPU in 0.347 seconds (97% CPU, 2332281 Lips)
L = [_G23, _G26, _G29, _G32, _G35, _G38, _G41, _G44, _G47|...],
N = 1000.

?- length(L,1000), time(length3(L,N)).
% 127,006 inferences, 0.047 CPU in 0.058 seconds (81% CPU, 2719603 Lips)
L = [_G23, _G26, _G29, _G32, _G35, _G38, _G41, _G44, _G47|...],
N = 1000.

*/

1
投票

使用reflection predicates可以构建以下list_length/2变体:

:- use_module(library(clpfd)).

list_length(Es, N) :-
   (  fd_sup(N, Ub), integer(Ub)
   -> (  length(Es, M),
         (  M >= Ub
         -> !,
            M == Ub
         ;  true
         ),
         M = N
      )
   ;  length(Es, N)
   ).

上面的实现结合了两个不错的属性:

  • 它适用于。 特别是,当list_length(Xs,N)具有有限的上界时,N普遍终止。 使用SWI-Prolog 8.0.0: ? - N in 1..3,list_length(Xs,N)。 N = 1,Xs = [_ A]; N = 2,Xs = [_ A,_ B]; N = 3,Xs = [_ A,_B,_C]。 %普遍终止
  • 它通过使用内置谓词length/2来最小化辅助计算(从而最小化运行时)。 让我们将list_length/2的运行时间与length3/2中提供的this earlier answer进行比较! 使用SWI-Prolog 8.0.0和命令行选项-O: ? - 时间((N in 1..100000,list_length(_,N),false; true))。 %2,700,130次推断,0.561秒内0.561 CPU(100%CPU,4812660 Lips)为真。 ? - 时间((N in 1..100000,length3(_,N),false; true))。 %14,700,041推断,3.948 CPU,3.949秒(100%CPU,3723234 Lips)true。

请注意,上述内容也适用于SICStus Prolog:SWI的fd_sup/2在SICStus中称为fd_max/2

© www.soinside.com 2019 - 2024. All rights reserved.