Пролог удалить: не удаляет все элементы, которые объединяются с элементом
У меня проблема с SWI-Прологом 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 ответа
Msgstr "Удалить всех членов 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:
удалить (?List1,?Elem,?List2)
Истинно, когда Lis1 со всеми вхождениями Elem удаляет результаты в List2.
также, delete/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).
возможно?
проверить исключить /3, включить /3, раздел /4
Использовать мета-предикат texclude/3
в сочетании с утвердительным термином предикат равенства (=)/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).
Не совсем! Для наших следующих попыток мы будем использовать лямбда-выражения.
:- 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, _], _). ложь
Этот ответ пытается обобщить идею, представленную в предыдущем ответе.
Давайте определим уточненный вариант 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)