Программа Prolog для поиска равенства двух списков в любом порядке

Я хотел написать программу на Prolog, чтобы найти равенство двух списков, где порядок элементов
не имеет значения. Поэтому я написал следующее:--5-->

del(_, [], []) .
del(X, [X|T], T).  
del(X, [H|T], [H|T1]) :-
   X = H,
   del(X, T, T1).

member(X, [X|_]).  
member(X, [_|T]) :- 
   member(X, T).

equal([], []).  
equal([X], [X]).  
equal([H1|T], L2) :-
   member(H1, L2),
   del(H1, L2, L3),
   equal(T, L3).  

но когда я даю ввода типа equal([1,2,3],X)., он не показывает все возможные значения X. Вместо этого программа висит посередине. Какая может быть причина?

9 ответов


isSubset([],_).
isSubset([H|T],Y):-
    member(H,Y),
    select(H,Y,Z),
    isSubset(T,Z).
equal(X,Y):-
    isSubset(X,Y),
    isSubset(Y,X).

попробуйте использовать предикат, который проверяет, является ли один из наборов перестановкой другого набора:

delete(X, [X|T], T).

delete(X, [H|T], [H|S]):-
    delete(X, T, S).


permutation([], []).

permutation([H|T], R):-
    permutation(T, X), delete(H, R, X).

(сказуемое взято из http://www.dreamincode.net/code/snippet3411.htm)

?- permutation([1,2,3],[3,1,2]).
true 

фактическая причина прекращения, которую вы наблюдали, заключается в следующем: следующий пункт не ограничивает L2 в любом случае, форма или форма.

equal([H1|T], L2) :- 
   member(H1, L2),
   del(H1, L2, L3),
   equal(T, L3).

Итак, ваш запрос ?- equal([1,2,3], X). подразумевает доказательство цели member(_, L2), который не прекращается повсеместно. Поэтому equal([1,2,3], X) не может закончиться универсально, тоже!

для получения дополнительной информации о том, как объяснить прекращение кода Prolog, прочитайте о сбой-slice!


PS. Рассматривая проблему завершения под другим углом, мы видим, что не-завершение, по сути, является необходимым следствием в этом случае.

почему? Потому что вы не ограничиваете количество кратностей, что делает решение бесконечным по размеру. Набор не может быть представлен конечным числом ответов (при условии, что вы не позволяете откладывать цели).


Если вы не заботитесь о кратностях элементов списка и используете только предикат с достаточным экземпляром, подумайте об этом следующим образом:

same_elements(As,Bs) :-
   (  ground(As+Bs)
   -> maplist(sort, [As,Bs], [Es,Es])      % same as `sort(As,Es), sort(Bs,Es)`
   ;  throw(error(instantiation_error,_))
   ).

попробуйте это:

equal([],[]).
equal([Ha|Ta],[Hb|Tb]) :-
   Ha = Hb, lequal(Ta,Tb).

Как насчет:

equal(X, Y) :-
    subtract(X, Y, []),
    subtract(Y, X, []).

почему equal([1,2,3], X) не завершается универсально с вашим кодом?

рассмотрим сбой-slice ваш код! Что такое ломтики отказа? Вот тегов:

срез отказа-это фрагмент программы пролога, полученный путем добавления некоторых целей false. Отказ-срезы помогают локализовать причины универсального не-завершения чистой монотонной программы пролога. Они также помогают дать нижнюю границу для количества необходимых выводов. Он это бетон должны изменить по крайней мере один из остальные части (не зачеркнута)!


Я предлагаю использовать встроенный предикат msort/2, затем сравнение списков. Это занимает O(nlogn) время в SWI Prolog, тогда как проверка несортированных списков наивно элемент за элементом займет O(n2


коротко

equal([],[]).
equal([H|T],[H|T1]):-equal(T,T1).