-
I saw this relationship in a Prolog book: delete_all([],_,[]).
delete_all([X|L1], L2, Diff) :-
member(X, L2), !,
delete_all(L1, L2, Diff).
delete_all([X|L1], L2, [X|Diff]) :-
delete_all(L1, L2, Diff). **Edit: ** (updated spacing, appreciated @UWN . Code mistakes remain mine!) Despite the name I started the conversation in another discussion but it was getting off track, so I'm moving the discussion here. @UWN pointed out that he answered a nearly identical question on SO, and I'm working on using |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 4 replies
-
It also does not work correctly with the cut. For example: ?- delete_all([A], "a", As). A = a, As = [], unexpected, incomplete. ?- A = b, delete_all([A], "a", As). A = b, As = "b". % expected |
Beta Was this translation helpful? Give feedback.
-
(Do not use empty lines between clauses of the same predicate. Use empty lines to separate different predicates only.) |
Beta Was this translation helpful? Give feedback.
-
So by "generate and test" I came up with this: % xs_ts_setdiff(Xs, Ys, Diff): Diff is the elements of Xs without the elements of Ys
xs_ys_setdiff([], _, []).
xs_ys_setdiff([X|Xs], Ys, Diff0) :-
if_(memberd_t(X, Ys),
(
xs_ys_setdiff(Xs, Ys, Diff0)
),
(
Diff0=[X|Diff],
xs_ys_setdiff(Xs, Ys, Diff)
)
).
?- xs_ys_setdiff([1, 2, 3], [2, 3, 5], Diff).
%@ Diff = [1].
?- xs_ys_setdiff([1, 2, 3, 4, 3], [3, 5], Diff).
%@ Diff = [1,2,4].
?- length(Xs, _), xs_ys_setdiff(Xs, Ys, Diff).
%@ Xs = [], Diff = []
%@ ; Xs = [_A], Ys = [], Diff = [_A]
%@ ; Xs = [_A], Ys = [_A|_B], Diff = []
%@ ; Xs = [_B], Ys = [_A], Diff = [_B], dif:dif(_A,_B)
%@ ; Xs = [_B], Ys = [_A,_B|_C], Diff = [], dif:dif(_A,_B)
%@ ; Xs = [_B], Ys = [_A,_C], Diff = [_B], dif:dif(_A,_B), dif:dif(_C,_B)
%@ ; Xs = [_B], Ys = [_A,_C,_B|_D], Diff = [], dif:dif(_A,_B), dif:dif(_C,_B)
%@ ; Xs = [_B], Ys = [_A,_C,_D], Diff = [_B], dif:dif(_A,_B), dif:dif(_C,_B), dif:dif(_D,_B)
%@ ; ... . I'm not sure if I'm happy that it seems to work or unhappy because I'm not sure why it works. As an experiment, I set this up: % xs_ts_setdiff(Xs, Ys, Diff): Diff is the elements of Xs without the elements of Ys
xs_ys_setdiff([], _, []).
xs_ys_setdiff([X|Xs], Ys, Diff) :-
memberd_t(X, Ys, true),
xs_ys_setdiff(Xs, Ys, Diff).
xs_ys_setdiff([X|Xs], Ys, [X|Diff]) :-
memberd_t(X, Ys, false),
xs_ys_setdiff(Xs, Ys, Diff).
?- xs_ys_setdiff([1, 2, 3], [2, 3, 5], Diff).
%@ Diff = [1]
%@ ; false.
?- xs_ys_setdiff([1, 2, 3, 4, 3], [3, 5], Diff).
%@ Diff = [1,2,4]
%@ ; false.
?- length(Xs, N), length(Ys, N), xs_ys_setdiff(Xs, Ys, Diff).
%@ Xs = [], N = 0, Ys = [], Diff = []
%@ ; Xs = [_A], N = 1, Ys = [_A], Diff = []
%@ ; Xs = [_B], N = 1, Ys = [_A], Diff = [_B], dif:dif(_A,_B)
%@ ; Xs = [_A,_A], N = 2, Ys = [_A,_B], Diff = []
%@ ; Xs = [_A,_B], N = 2, Ys = [_A,_B], Diff = [], dif:dif(_A,_B)
%@ ; Xs = [_A,_B], N = 2, Ys = [_A,_C], Diff = [_B], dif:dif(_A,_B), dif:dif(_C,_B)
%@ ; ... . which seems to work as well, but with redundant choice points. It is very interesting that the two implementations are not identical! Referring to the top/first implementation of ?- length(Ls, _), xs_ys_setdiff([1, 2, 3], Ls, [2, 3, 5]).
%@ nontermination I feel like if |
Beta Was this translation helpful? Give feedback.
-
This was the original version.
Which only deletes one element deletealls([], _Xs, []). deletealls([E|Es], Xs, Ys0) :- if_( memberd_t(E, Xs), Ys0 = Ys, Ys0 = [E|Ys] ), deletealls(Es, Xs, Ys). ?- deletealls([A,B,C,A,C],[A],Es). A = B, C = A, Es = [] ; A = B, Es = [C,C], dif:dif(A,C) ; A = C, Es = [B], dif:dif(A,B) ; Es = [B,C,C], dif:dif(A,C), dif:dif(A,B). ?- deletealls([A,B,C,A,C],[A,B],Es). A = B, C = A, Es = [] ; A = B, Es = [C,C], dif:dif(A,C) ; A = C, Es = [], dif:dif(A,B) ; B = C, Es = [], dif:dif(A,B) ; Es = [C,C], dif:dif(A,C), dif:dif(A,B), dif:dif(B,C). To understand termination, you need first to master the notion of a failure slice. Now in your case of
before looking into the actual implementation, just think of how an answer should look like.
Now from the viewpoint of the implementation, we have the following failure slice: ?- deletealls("abc",Ys,"a"), false. loops. In case of doubt, opt for better termination than fair enumeration. For, better termination permits us to enumerate solutions manually, whereas a definition that favors fair enumeration cannot be made to terminate. |
Beta Was this translation helpful? Give feedback.
-
A case of fair enumeration:
Note how the positive and negative answers are almost the same, except for that tiny detail at the end... |
Beta Was this translation helpful? Give feedback.
This was the original version.
Which only deletes one element
X
. But we want to delete all elements ofXs
. So we have to replace the condition(=)/3
above by a more sophisticated condition.