Prolog delete:不删除与Element统一的所有元素

时间:2011-11-11 22:10:59

标签: list prolog

我遇到SWI-Prolog的delete/3谓词问题。 最简单的方法只是一个简单的例子:

?- delete([(1,1),(1,2),(3,2)], (1,_), List).
List = [(1,2),(3,2)].

由于(1,2)(1,_)统一,我希望也会删除(1,2)。 SWIPL帮助说:

  

删除同时与List1统一的Elem所有成员,并将结果与​​List2统一。

为什么会这样,如何删除与(1,_)统一的所有内容?

3 个答案:

答案 0 :(得分:3)

“删除List1中同时与Elem统一的所有成员,并将结果与​​List2统一。”

(1,X)首先与(1,1)结合。因此,X与1统一,不能与2统一删除(1,2)。 所以问题不在于它不会删除所有成员;它与(1,2)和(1,1)不同时统一 (尝试删除([(1,1),(1,2),(1,1),(3,2)],(1,_),List)。

btw,根据swi-prolog manual

  
    

删除(?List1,?Elem,?List2)
        当所有出现的Elem被删除时Lis1中的Lis1结果为真。

  

同样,不推荐使用delete / 3:

  

有太多方法可能需要从列表中删除元素以证明名称的合理性。   考虑匹配(=与==),删除第一个/所有,是否确定。

所以最简单的方法是编写自己的谓词。类似的东西:

my_delete(Pattern,[Pattern|T],TD):-
   my_delete(Pattern,T,TD).
my_delete(Pattern,[H|T],[H|TD]):-
   my_delete(Pattern,T,TD).

也许?

检查exclude/3, include/3, partition/4

答案 1 :(得分:2)

结合使用 texclude/3 reified term equality predicate (=)/3

首先,我们尝试直接使用(=)/3 ...

?- texclude(=((1,V)), [(1,1),(1,2),(3,2)], KVs).
KVs = [      (1,2),(3,2)],     V=1            ;
KVs = [(1,1),      (3,2)],               V=2  ;
KVs = [(1,1),(1,2),(3,2)], dif(V,1), dif(V,2).

不完全!对于我们的下一次尝试,我们将使用lambda expressions

:- use_module(library(lambda)).

让我们查询---一次使用texclude/3,一次使用tinclude/3,一次使用tpartition/4

?- texclude(  \ (K,_)^(K=1), [(1,1),(1,2),(3,2)], Fs).
Fs = [(3,2)].                                     % succeeds deterministically

?- tinclude(  \ (K,_)^(K=1), [(1,1),(1,2),(3,2)], Ts).
Ts = [(1,1),(1,2)].                               % succeeds deterministically

?- tpartition(\ (K,_)^(K=1), [(1,1),(1,2),(3,2)], Ts,Fs).
Ts = [(1,1),(1,2)], Fs = [(3,2)].                 % succeeds deterministically

好吧!如果在<{em> texclude/3电话之后绑定了列表项,我们是否会获得相同的解决方案?

?- texclude(\ (K,_)^(K=1), [A,B,C], Fs), A = (1,1), B = (1,2), C = (3,2).
A = (1,1), B = (1,2), C = (3,2), Fs = [(3,2)] ;   % succeeds with choice point
false.

是的!最后,请考虑以下非常一般的问题:

?- texclude(\ (K,_)^(K=1), [A,B], Fs).
Fs = [   ], A = (  1,_A1), B = (  1,_B1)                         ;
Fs = [  B], A = (  1,_A1), B = (_B0,_B1),             dif(_B0,1) ;
Fs = [A  ], A = (_A0,_A1), B = (  1,_B1), dif(_A0,1)             ;
Fs = [A,B], A = (_A0,_A1), B = (_B0,_B1), dif(_A0,1), dif(_B0,1).

请注意,上述目标会将所有列表项限制为(_,_)。因此,以下查询失败:

?- texclude(\ (K,_)^(K=1), [x,_], _).
false.

答案 2 :(得分:1)

这个答案试图概括previous answer中提出的想法。

让我们定义subsumes_term/2的具体变体:

list_nonvardisj([A],C) :- 
   !, 
   C = nonvar(A).
list_nonvardisj([A|As],(nonvar(A);C)) :-
   list_nonvardisj(As,C).

subsumes_term_t(General,Specific,Truth) :-
   subsumes_term(General,Specific),
   !,
   term_variables(General,G_vars),
   free4evrs(G_vars),
   Truth = true.
subsumes_term_t(General,Specific,Truth) :-
   Specific \= General,
   !,
   Truth = false.
subsumes_term_t(General,Specific,Truth) :-
   term_variables(Specific,S_vars),
   (  S_vars = [V]
   -> freeze(V,subsumes_term_t(General,Specific,Truth))
   ;  S_vars = [_|_]
   -> list_nonvardisj(S_vars,S_wakeup),
      when(S_wakeup,subsumes_term_t(General,Specific,Truth))
   ;  throw(error(instantiation_error, subsumes_term_t/3))
   ),
   (  Truth = true
   ;  Truth = false
   ).

上述定义谓词subsumes_term_t/3的定义使用free4evrs/1来确保传递给subsumes_term/2的“通用”术语不再被实例化。

对于SICStus Prolog,我们可以按如下方式定义:

:- module(free4evr,[free4evr/1,free4evrs/1]).

:- use_module(library(atts)).

:- attribute nvrb/0.                       % nvrb ... NeVeR Bound

verify_attributes(V,_,Goals) :-
   get_atts(V,nvrb), 
   !,
   Goals = [throw(error(uninstantiation_error(V),free4evr/1))].
verify_attributes(_,_,[]).

attribute_goal(V,free4evr(V)) :-
   get_atts(V,nvrb).

free4evr(V) :-
   nonvar(V),
   !,
   throw(error(uninstantiation_error(V),free4evr/1)).
free4evr(V) :-
   (  get_atts(V,nvrb)
   -> true
   ;  put_atts(Fresh,nvrb),
      V = Fresh
   ).

free4evrs([]).
free4evrs([V|Vs]) :-
   free4evr(V),
   free4evrs(Vs).

让我们使用subsumes_term_t/3

?- texclude(subsumes_term_t(1-X), [A,B,C], Fs), A = 1-1, B = 1-2, C = 3-2.
A = 1-1, B = 1-2, C = 3-2, Fs = [C], free4evr(X) ? ;   % succeeds with choice-point
no

?- texclude(subsumes_term_t(1-X), [x,1-Y,2-3], Fs).
Fs = [x,2-3], free4evr(X) ? ;
no

如果我们在调用X后的某个时间在上述查询中实例化变量texclude/3会怎样?

?- texclude(subsumes_term_t(1-X), [x,1-Y,2-3], Fs), X=something.
! error(uninstantiation_error(something),free4evr/1)