Prolog程序中的结果无效

时间:2015-01-16 07:44:49

标签: recursion prolog

我的程序旨在消除列表中的重复元素。我认为是正确的。 我尝试通过切割来使其工作,但它没有给出正确的结果。

member(X,[X|_]). % If X is Head, it is a member
member(X,[_|T]) :- member(X,T). % If not, Recursively check the tail.

remove_duplicates([],[]).
remove_duplicates([H|T],R):-member(H,T),remove_duplicates(T,R).
remove_duplicates([H|T],[R|REM]):-remove_duplicates(T,REM).

但是我得到了结果:I = [_G2608, _G2611, _G2614|_G2615] 输入remove_duplicates([a,b,a,b,b,c],I)

2 个答案:

答案 0 :(得分:3)

这个版本既纯粹又高效,因为它只需要恒定的辅助空间。到目前为止发布的解决方案在最坏的情况下需要与第一个参数中列表大小成比例的空间。但现在要正确:

?- remove_duplicates([A,B], Fs).

我们在这里问:

  

AB必须如何产生一个没有重复的列表Fs

这个问题不能简单地通过陈述具体Fs来解答,因为Fs可能是[A,B][A] AB是一样的。

?- remove_duplicates([A,B],F).
   A = B,
   F = [B]
;  F = [A, B],
   dif(A, B).

这是一个解决方案。此定义需要another answer中定义的单调if_/3memberd_truth/3

remove_duplicates([], []).
remove_duplicates([E|Es], Fs0) :-
   if_( memberd_truth(E, Es) , Fs0 = Fs , Fs0 = [E|Fs] ),
   remove_duplicates(Es, Fs).

就个人而言,我更希望使用更多关系名称,例如list_unique/2list_nub/2作为暗示towards Haskell

答案 1 :(得分:2)

都铎的解决方案很好。但是,我已经看到了在适当的情况下使用条件语句的好处,即使我发现美学有点缺乏,所以我建议改为:

remove_duplicates([], []).
remove_duplicates([H|T], R) :-
  (   memberchk(H,T)
  ->  remove_duplicates(T, R)
  ;   remove_duplicates(T, R0), 
      R = [H|R0]
  ).

像这样的显式条件不会产生虚假的选择点。正是这个选择点导致都铎的解决方案需要一个否定的member/2,你试图通过削减进行纠正。因此即使它看起来不那么漂亮,它也是一种更有效的解决方案。

此外,对于您不需要memberchk/2生成解决方案的情况,使用member/2代替member/2是一个小优化。比较:

?- time(remove_duplicates([a,b,a,b,b,c], I)).
% 14 inferences, 0.000 CPU in 0.000 seconds (96% CPU, 1037114 Lips)
I = [a, b, c].

到都铎的代码修订版:

?- time(remove_duplicates([a,b,a,b,b,c], I)).
% 28 inferences, 0.000 CPU in 0.000 seconds (94% CPU, 2264822 Lips)
I = [a, b, c] ;
% 28 inferences, 0.000 CPU in 0.000 seconds (92% CPU, 1338752 Lips)
I = [a, b, c] ;
% 15 inferences, 0.000 CPU in 0.000 seconds (88% CPU, 1065341 Lips)
false.