如果你看一个具体的例子,你很快就会被许多不相关的细节所淹没。如此之多,以至于您将忽略程序的重要属性。让我们看看下面的程序片段,它被称为故障片。false
通过将目标添加到程序中,您将获得失败部分。失败切片与原始程序有许多有趣的属性。例如,Goal, false
使用失败切片执行的目标永远不会使用比原始程序更多的推理。或者相反,原始程序将使用更多(或最多相同数量)的推理。所以,让我指出这样一个片段:
list_to_set([],[]) :-假。
list_to_set([A|X],[A|Y]):-
list_to_set(X,Y), false ,
\+member(A,Y)。
list_to_set([A|X],Y):-
list_to_set(X,Y), false ,
member(A,Y)。
而且由于这个片段不再对具体元素感兴趣(A
不再使用,也不再member/2
),我们可以使用length/2
最通用的列表。通过这种方式,我们可以观察到每个长度所需的最少推理次数,如下所示:
?-长度(L,N),call_inferences((list_to_set(L,_),false;true),Inf)。
N = 0,Inf = 3;
N = 1,Inf = 6;
N = 2, Inf = 12 ;
N = 3,Inf = 24;
N = 4,Inf = 48;
N = 5,Inf = 96;
N = 6,Inf = 192;
N = 7,Inf = 384;
N = 8,Inf = 768;
N = 9,Inf = 1536;
N = 10,Inf = 3072 ...
使用
:- meta_predicate user:call_inferences(0,-).
call_inferences( Goal, Inferences) :-
statistics(inferences, Inferences0),
Goal,
statistics(inferences, Inferences1),
Inferences is Inferences1 - Inferences0.
每增加一个元素,推理的数量就会增加一倍。也就是说,它们呈指数增长。因此,您的实现至少要花费成倍的推论……无需查看具体示例。
您的程序中还有更多问题:
?- L=[A,B],list_to_set(L,S), L = [a,b].
失败,而
?- L=[A,B], L = [a,b], list_to_set(L,S).
成功。也就是说,您的程序不再是纯粹的关系。maplist(dif(A),Y)
代替\+ member(A,Y)
. _