Удаление элемента или списка в SWI-Prolog

Еще проблема, у меня есть хорошая рабочая "функция" для удаления:

remove([],X,[]) :- !. 
remove([X|T],X,L1) :- !, remove(T,X,L1).         
remove([H|T],X,[H|L1]) :- remove(T,X,L1). 

Но это не работает так, как я хочу, чтобы это работало. Он удаляет элемент или даже список...

... но не удаляет все проявления. Это цель:

remove([A,B,[C],[A,[B]],[[A,[B]]]],[A,[B]],X).
X=[A,B,[C],[]]

Любые идеи?


person Nolog Lester    schedule 08.04.2012    source источник


Ответы (1)


Если вы хотите удалить все появления, например, чтобы позволить remove([1,2,3,1],1,X) вычислить X=[2,3], просто замените второе предложение на

 remove([X|T],X,L1) :- remove(T,X,L1), !.  

Однако кажется, что вы хотели бы: а) работать с переменными, которые должны храниться как переменные, и б) удалять списки из подсписков.

Сначала мы начнем с решения вопроса б).

remove([],_,[]) :- !. 
remove(A,_,A) :- \+ (A = [_|_]), !.
remove([X|T],X,L1) :- remove(T,X,L1), !.        
remove([H|T],X,[G|L1]) :- remove(H,X,G), remove(T,X,L1).

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

Наконец, для решения а) нужно использовать предикаты «заморозить»/«растопить» Стерлинга и Шапиро. Freeze заменяет переменные выражениями #VAR(0), #VAR(1), ..., а Mel делает обратное. Melt традиционно известен как Melt_new.

numvars('#VAR'(N),N,N1) :- N1 is N+1.
numvars(Term,N1,N2) :- nonvar(Term), functor(Term,_,N),
                          numvars(0,N,Term,N1,N2).

numvars(N,N,_,N1,N1).
numvars(I,N,Term,N1,N3) :- I<N, I1 is I+1,
          arg(I1,Term,Arg), numvars(Arg,N1,N2),
          numvars(I1,N,Term,N2,N3).

frz(A,B) :- frz(A,B,0).
frz(A,B,Min) :- copy_term(A,B), numvars(B,Min,_),!.


melt_new(A,B) :-
   melt(A,B,Dictionary), !.

melt('$VAR'(N),X,Dictionary) :-
    lookup(N,Dictionary,X).
melt(X,X,Dictionary) :-
    constant(X).
melt(X,Y,Dictionary) :-
    compound(X),
    functor(X,F,N),
    functor(Y,F,N),
    melt(N,X,Y,Dictionary).

melt(N,X,Y,Dictionary) :-
    N > 0, 
    arg(N,X,ArgX), 
    melt(ArgX,ArgY,Dictionary),
    arg(N,Y,ArgY), 
    N1 is N-1, 
    melt(N1,X,Y,Dictionary).
melt(0,X,Y,Dictionary).

/*  
    lookup(Key,Dictionary,Value) :-
    Dictionary contains the value indexed under Key.
    Dictionary is represented as an ordered binary tree.

*/

    lookup(Key,dict(Key,X,Left,Right),Value) :-
        !, X = Value.
    lookup(Key,dict(Key1,X,Left,Right),Value) :-
        Key < Key1 , lookup(Key,Left,Value).
    lookup(Key,dict(Key1,X,Left,Right),Value) :-
        Key > Key1, lookup(Key,Right,Value).

Кстати, очень рекомендую книгу Стерлинга и Шапиро "Искусство Пролога". Плавление и замораживание обсуждаются в главе 15.

person Alexander Serebrenik    schedule 08.04.2012
comment
Большое спасибо за исчерпание кода! О первом (более простом) выпуске. Вот что я получаю: ?- remove([A,B,[C],[A,[B]],[[A,[B]]]],[A,[B]],X). A = B, B = C, C = [C, [C]], X = [[], []]. Это немного странно. Почему это так? - person Nolog Lester; 09.04.2012
comment
Ответ, который вы получаете, связан с непреднамеренным объединением. Предикат удаления, как определено выше, будет работать, как вы ожидаете, только для списков (списков) основных терминов (= терминов без переменных). Если вы хотите применить его к неосновному случаю, вам сначала нужно сделать условия заземленными (заморозить), затем вызвать remove/3 и, наконец, вернуться к неосновному случаю (melt_new). - person Alexander Serebrenik; 09.04.2012
comment
@AlexanderSerebrenik для меня работает простая модификация (ниже). Но даже используя трассировку, я все еще не понимаю, как именно работает рекурсия. Не могли бы вы пройтись по приведенному ниже примеру? without([],_X,[]) :- !. without([X|T],X,Result) :- !, without(T,X,Result). without([H|T],X,[H|Result]) :- without(T,X,Result). Используя запрос: without([1,3,5], 3, X) - person mdo123; 06.12.2016