Deleting all members of a list without unification in Prolog

387 Views Asked by At

Possible Duplicate:
Prolog delete: doesn't delete all elements that unify with Element

In Prolog if you write this:

delete([(1,1),(1,2),(1,1),(3,4)],(1,_),L).

the result will be:

L = [ (1, 2), (3, 4)].

What is normal because the _ variable binds with 1 in the first element and it searches for further elements of (1,1) and deletes them.

Is there a way to prevent this unification from happening and deleting all members of the form (1,_). In that case the result must be: L = [ (3, 4)].

2

There are 2 best solutions below

1
On BEST ANSWER
delete_pattern([], _, []).
delete_pattern([H|T], P, O) :-
    (    H \= P
    ->   O = [H|O1],
         delete_pattern(T, P, O1)
    ;    delete_pattern(T, P, O) ).

You may like to use other predicates for filtering that would result in slightly different semantics as ==/2 or =@=/2.

1
On

Here is a another version. Actually, a pure one:

list_el_deleted([], _, []).
list_el_deleted([X|Xs], X, Ys) :-
   list_el_deleted(Xs, X, Ys).
list_el_deleted([X|Xs], E, [X|Ys]) :-
   dif(X,E),
   list_el_deleted(Xs, E, Ys).

Trying it on your query reveals the actual sources of ambiguity in your problem statement:

?- list_el_deleted([(1,1),(1,2),(1,1),(3,4)],(1,X),L).
   X = 1, L = [(1,2),(3,4)]
;  X = 2, L = [(1,1),(1,1),(3,4)]
;  L = [(1,1),(1,2),(1,1),(3,4)], dif(X,1), dif(X,2), dif(X,1).

So it all depends on what X actually is: 1, 2, or something else. Note that the previous versions discussed here depend on the actual instantiation which makes reasoning much more difficult:

?- delete([a],X, Xs), X = c.
   false.
?- X = c, delete([a],X, Xs).
   X = c, Xs = [a].