2011-11-11 88 views
3

我遇到了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

「刪除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,_),列表)

順便說一句,根據swi-prolog manual:???

刪除(列表1,ELEM,列表2)
是真的時LIS1,與ELEM出現的所有在列表2中刪除結果

也刪除/ 3不推薦使用:

人們可能想從列表中刪除元素以證明名稱的方式太多。 想想匹配(= vs. ==),先刪除/全部,確定性與否。

所以最簡單的方法是編寫自己的謂詞。例如:

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

+0

「my_delete/3」的所有子句都是遞歸的,這太多了:) – repeat

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 

好吧!如果列表項是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. 
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 

如果我們調用texclude/3後的某個時間在上面的查詢實例變量X會發生什麼?

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