Remove brackets from a list in Prolog [duplicate] - list

I am doing some easy exercises to get a feel for the language.
is_list([]).
is_list([_|_]).
my_flatten([],[]).
my_flatten([X|Xs],RR) :-
my_flatten(Xs,R),
(is_list(X), !, append(X,R,RR); RR = [X | R]).
Here is a version using cut, for a predicate that flattens a list one level.
my_flatten([],[]).
my_flatten([X|Xs],RR) :-
my_flatten(Xs,R),
if_(is_list(X), append(X,R,RR), RR = [X | R]).
Here is how I want to write it, but it does not work. Neither does is_list(X) = true as the if_ condition. How am I intended to use if_ here?

(Sorry, I somewhat skipped this)
Please refer to P07. It clearly states that it flattens out [a, [b, [c, d], e]], but you and #Willem produce:
?- my_flatten([a, [b, [c, d], e]], X).
X = [a,b,[c,d],e]. % not flattened!
And the solution given there succeeds for
?- my_flatten(non_list, X).
X = [non_list]. % unexpected, nothing to flatten
Your definition of is_list/1 succeeds for is_list([a|non_list]). Commonly, we want this to fail.
What you need is a safe predicate to test for lists. So let's concentrate on that first:
What is wrong with is_list/1 and if-then-else? It is as non-monotonic, as many other impure type testing predicates.
?- Xs = [], is_list([a|Xs]).
Xs = [].
?- is_list([a|Xs]). % generalization, Xs = [] removed
false. % ?!? unexpected
While the original query succeeds correctly, a generalization of it unexpectedly fails. In the monotonic part of Prolog, we expect that a generalization will succeed (or loop, produce an error, use up all resources, but never ever fail).
You have now two options to improve upon this highly undesirable situation:
Stay safe with safe inferences, _si!
Just take the definition of list_si/1 in place of is_list/1. In problematic situations, your program will now abort with an instantiation error, meaning "well sorry, I don't know how to answer this query". Be happy for that response! You are saved from being misled by incorrect answers.
In other words: There is nothing wrong with ( If_0 -> Then_0 ; Else_0 ), as long as the If_0 handles the situation of insufficient instantiations correctly (and does not refer to a user defined program since otherwise you will be again in non-monotonic behavior).
Here is such a definition:
my_flatten(Es, Fs) :-
list_si(Es),
phrase(flattenl(Es), Fs).
flattenl([]) --> [].
flattenl([E|Es]) -->
( {list_si(E)} -> flattenl(E) ; [E] ),
flattenl(Es).
?- my_flatten([a, [b, [c, d], e]], X).
X = [a,b,c,d,e].
So ( If_0 -> Then_0 ; Else_0 ) has two weaknesses: The condition If_0 might be sensible to insufficient instantiations, and the Else_0 may be the source of non-monotonicity. But otherwise it works. So why do we want more than that?
In many more general situations this definition will now bark back: "Instantiation error"! While not incorrect, this still can be improved. This exercise is not the ideal example for this, but we will give it a try.
Use a reified condition
In order to use if_/3 you need a reified condition, that is, a definition that carries it's truth value as an explicit extra argument. Let's call it list_t/2.
?- list_t([a,b,c], T).
T = true.
?- list_t([a,b,c|non_list], T).
T = false.
?- list_t(Any, T).
Any = [],
T = true
; T = false,
dif(Any,[]),
when(nonvar(Any),Any\=[_|_])
; Any = [_],
T = true
; Any = [_|_Any1],
T = false,
dif(_Any1,[]),
when(nonvar(_Any1),_Any1\=[_|_])
; ... .
So list_t can also be used to enumerate all true and false situations. Let's go through them:
T = true, Any = [] that's the empty list
T = false, dif(Any, []), Any is not [_|_] note how this inequality uses when/2
T = true, Any = [_] that's all lists with one element
T = true, Any = [_|_Any1] ... meaning: we start with an element, but then no list
list_t(Es, T) :-
if_( Es = []
, T = true
, if_(nocons_t(Es), T = false, ( Es = [_|Fs], list_t(Fs, T) ) )
).
nocons_t(NC, true) :-
when(nonvar(NC), NC \= [_|_]).
nocons_t([_|_], false).
So finally, the reified definition:
:- meta_predicate( if_(1, 2, 2, ?,?) ).
my_flatten(Es, Fs) :-
phrase(flattenl(Es), Fs).
flattenl([]) --> [].
flattenl([E|Es]) -->
if_(list_t(E), flattenl(E), [E] ),
flattenl(Es).
if_(C_1, Then__0, Else__0, Xs0,Xs) :-
if_(C_1, phrase(Then__0, Xs0,Xs), phrase(Else__0, Xs0,Xs) ).
?- my_flatten([a|_], [e|_]).
false.
?- my_flatten([e|_], [e|_]).
true
; true
; true
; ... .
?- my_flatten([a|Xs], [a]).
Xs = []
; Xs = [[]]
; Xs = [[],[]]
; ... .
?- my_flatten([X,a], [a]).
X = []
; X = [[]]
; X = [[[]]]
; X = [[[[]]]]
; ... .
?- my_flatten(Xs, [a]).
loops. % at least it does not fail

In Prolog, the equivalen of an if … then … else … in other languages is:
(condition -> if-true; if-false)
With condition, if-true and if-false items you need to fill in.
So in this specific case, you can implement this with:
my_flatten([],[]).
my_flatten([X|Xs],RR) :-
my_flatten(Xs,R),
( is_list(X)
-> append(X,R,RR)
; RR = [X | R] ).
or we can flatten recursively with:
my_flatten([],[]).
my_flatten([X|Xs],RR) :-
my_flatten(Xs,R),
( flatten(X, XF)
-> append(XF,R,RR)
; RR = [X | R] ).
Your if_/3 predicate is used for reified predicates.

This worked for me:
myflat([], []).
myflat([H|T], L) :-
myflat(H, L1),
myflat(T, L2),
append(L1, L2, L).
myflat(L, [L]).

Related

Get elements of arbitrary nested lists

I am looking for some predicate in SWI-Prolog to get the elements of some arbitrary nested list. Means, if I e.g. have the list:
L = [[a,b], c, [d, [e, f]]]
I get as result:
R = [a,b,c,d,e,f]
The SWI built-in predicate flatten/2 depends on the very instantiations of the first argument. It thus leads to quite non-relational behavior:
?- flatten(X,[]).
false.
?- X = [], flatten(X,[]).
X = [].
?- X = [[],[]], flatten(X,[]).
X = [[], []].
?- X = [[]|[]], flatten(X,[]).
X = [[]].
Note that there are infinitely many X to make flatten(X,[]) succeed. If you want this to be a relation, there are two choices either enumerate all such solutions, or produce an instantiation error, or just do not terminate (better than an incorrect answer), or delay goals appropriately, or produce some constraints, or produce a resource error. Oh, these have been now 6 choices... ...and lest I forget, you might also combine these options, like first producing some answer substitutions, then delayed goals, then constraints, and then loop quite some time to finally produce a resource error.
In most of such situations, the easiest way to go is to produce instantiation errors like so:
flattened(T) -->
{functor(T,_,_)}, % ensures instantiation
( {T = [E|Es]} -> flattened(E), flattened(Es)
; {T = []} -> []
; [T]
).
?- phrase(flattened([[]|[]]),Xs).
Xs = [].
?- phrase(flattened([[]|_]),Xs).
error(instantiation_error,functor/3).
As #brebs mentioned in his comment, Use predefined predicate flatten/2
% ?- flatten([[a,b], c, [d, [e, f]]], R).
% R = [a, b, c, d, e, f]
This user-defined implementation is similar to the predefined one [1]
my_flatten([],[]).
my_flatten([H|T], [H|Res]) :- \+ is_list(H), my_flatten(T, Res), !.
my_flatten([H|T], Res) :- my_flatten(H, Res). % H is list.
[1] except for cases of non-termination like my_flatten(X,non_list). and like my_flatten([X],[1,2,3,4]). thanks to #false comment

Remove duplicates from a list while keeping the rightmost occurrences

I am trying to remove duplicates from a list while keeping the rightmost occurrences. E.g.: [1,2,3,1,2] is transformed in [3,1,2]
It's one of my first tries in Prolog and I don't understand what am I doing wrong. It always returns false. This is my code:
%nrap(L:list,E:element,S:integer)
%L - the initial list, list of integers
%E - the element, integer
%S - the result, nrap of E in L, S integer
%flow model: (i,i,o),(i,i,i)
nrap([],_,0).
nrap([H|T],E,S):-
H=E,
nrap(T,E,S1),
S is S1+1.
nrap([H|T],E,S):-
H\=E,
nrap(T,E,S).
%transform(L:list,L2:list,R:list)
%L - the initial list, list of integers
%L2 - copy of the initial list
%R - the resulted list, without duplicates, list of integers
%flow model: (i,i,o),(i,i,i)
transform([],[],[]).
transform([H|T],L2,[H|R]):-
nrap(L2,H,S),
S=1,
transform(T,L2,R).
transform([H|T],L2,R):-
nrap(L2,H,S),
S>1,
transform(T,L2,R).
Shall I be pure or impure? Why even consider sacrificing logical-purity if we can save it easily!
Using memberd_t/3 and if_/3, we define list_rset/2 and its left "twin" list_lset/2:
list_rset([], []). % keep rightmost occurrences
list_rset([E|Es], Rs0) :-
if_(memberd_t(E, Es),
Rs0 = Rs,
Rs0 = [E|Rs]),
list_rset(Es, Rs).
list_lset([], []). % keep leftmost occurrences
list_lset([E|Es], Ls) :-
post_pre_lset(Es, [E], Ls). % uses internal auxilary predicate
post_pre_lset([], _, []).
post_pre_lset([E|Es], Pre, Ls0) :- % 2nd arg: look-behind accumulator
if_(memberd_t(E, Pre),
Ls0 = Ls,
Ls0 = [E|Ls]),
post_pre_lset(Es, [E|Pre], Ls).
Let's run some queries!
?- _Es = [1,2,3,1,2], list_lset(_Es, Ls), list_rset(_Es, Rs).
Ls = [1,2,3], Rs = [3,1,2]. % succeeds deterministically
In above query 1 precedes 2 both at the beginning and at the end of the list [1,2,3,1,2]. What if 1 precedes 2 at the beginning but follows it at the end (e.g., [1,2,3,2,1])?
?- _Es = [1,2,3,2,1], list_lset(_Es, Ls), list_rset(_Es, Rs).
Ls = [1,2,3], Rs = [3,2,1]. % succeeds deterministically
Next, we look at a more general list_rset/2 goal that uses a list containing variables only. Thanks to #PauloMoura for his suggestion!
?- Es = [A,B,C,A,B], list_rset(Es,Rs).
Es = [C,C,C,C,C], Rs = [ C], A=B , B=C
; Es = [B,B,C,B,B], Rs = [C, B], A=B , dif(B,C)
; Es = [C,B,C,C,B], Rs = [ C,B], A=C , dif(B,C)
; Es = [A,C,C,A,C], Rs = [ A,C], dif(A,C), B=C
; Es = [A,B,C,A,B], Rs = [C,A,B], dif(A,B), dif(A,C), dif(B,C).
What's up with the residual goals (above)?
Without sufficient instantiation, dif/2 is not decidable.
To save logical soundness, the execution of the prolog-dif constraints is delayed.
Last, one more use-case: an "input" list Xs that has both variables and ground terms.
?- Es = [A,B,z], list_rset(Es,Rs).
Es = [z,z,z], Rs = [ z], A=B , B=z
; Es = [B,B,z], Rs = [B, z], A=B , dif(B,z)
; Es = [z,B,z], Rs = [ B,z], A=z , dif(B,z)
; Es = [A,z,z], Rs = [A, z], dif(A,z), B=z
; Es = [A,B,z], Rs = [A,B,z], dif(A,B), dif(A,z), dif(B,z).
This is a follow-up to this previous answer... In this answer we use dcg!
We build lset//1 upon memberd_t/3 and if_//3—the dcg analogue of if_/3:
lset([]) -->
[].
lset([X|Xs]) -->
[X],
lset_pre(Xs,[X]).
lset_pre([],_) -->
[].
lset_pre([X|Xs],Pre) -->
if_(memberd_t(X,Pre), [], [X]),
lset_pre(Xs,[X|Pre]).
Same for rset//1:
rset([]) -->
[].
rset([X|Xs]) -->
if_(memberd_t(X,Xs), [], [X]),
rset(Xs).
Some sample queries:
?- _Es = [1,2,3,1,2], phrase(lset(_Es),Ls), phrase(rset(_Es),Rs).
Ls = [1,2,3], Rs = [3,1,2]. % succeeds deterministically
?- _Es = [1,2,3,2,1], phrase(lset(_Es),Ls), phrase(rset(_Es),Rs).
Ls = [1,2,3], Rs = [3,2,1]. % succeeds deterministically
This is easier than you are making it. Since the elements in the "set" have to be in the order of last appearance, you don't need to keep a copy of the list at all: just compare to the remainder of the list (the tail).
If you know that the first list is always going to be ground (all elements are integers, for example), you could write:
list_set([], []).
list_set([X|Xs], Ys0) :-
( memberchk(X, Xs)
-> Ys0 = Ys
; Ys0 = [X|Ys]
),
list_set(Xs, Ys).
memberchk/2 can be used to check if a ground term is in a list of ground terms. It will succeed or fail exactly once.
A more general solution is to pose a constraint that an element should be in the set if it is different from all the elements following it, and be dropped otherwise:
list_set([], []).
list_set([X|Xs], [X|Ys]) :-
maplist(dif(X), Xs),
list_set(Xs, Ys).
list_set([X|Xs], Ys) :-
\+ maplist(dif(X), Xs),
list_set(Xs, Ys).
Here, maplist(dif(X), Xs) means:
X is different from every element in the list Xs (the tail).
and \+ Goal succeeds then Goal does not succeed.
With this defintion:
?- list_set([1,2,3,1,2], S).
S = [3, 1, 2] ;
false.
?- list_set([1,2,3,3,1,1,2], S).
S = [3, 1, 2] ;
false.
?- list_set([A,B,C,A,B],Xs).
Xs = [C, A, B],
dif(A, B),
dif(C, B),
dif(C, A) ;
false.

Element appears exactly once in the list in Prolog

I want to write a predicate which check if the Element appeares exactly once in the List.
once(Element, List).
My code:
once(X, [H | T]) :-
\+ X = H,
once(X, T).
once(X, [X | T]) :-
\+ member(X, T).
?- once(c, [b,a,a,c,b,a]).
true
?- once(b, [b,a,a,c,b,a]).
false.
But if I ask:
once(X, [b,a,a,c,b,a]).
Prolog answers:
false
Why? Prolog should find X = c solution. Where is bug?
Running a trace in prolog can be very helpful in determining the answer to this sort of question. We'll do the trace manually here for illustration.
Let's look at your predicate:
once(X, [H | T]) :-
\+ X = H,
once(X, T).
once(X, [X | T]) :-
\+ member(X, T).
Let's consider now the query:
once(X, [b,a,a,c,b,a]).
First, Prolog attempts the first clause of your predicate. The head is once(X, [H|T]) and first expression is \+ X = H, which will become:
once(X, [b|[a,a,c,b,a]]) :- % [H|T] instantiated with [b,a,a,c,b,a] here
% So, H is b, and T is [a,a,c,b,a]
\+ X = b,
...
X is instantiated (be unified with) with the atom b here, and the result of that unification succeeds. However, you have a negation in front of this, so the result of \+ X = b, when X is initially unbound, will be false since X = b unifies X with b and is true.
The first clause thus fails. Prolog moves to the next clause. The clause head is once(X, [X|T]) and following is \+ member(X, T), which become:
once(b, [b|[a,a,c,b,a]]) :- % X was instantiated with 'b' here,
% and T instantiated with [a,a,c,b,a]
\+ member(b, [a,a,c,b,a]).
member(b, [a,a,c,b,a]) succeeds because b is a member of [a,a,c,b,a]. Therefore, \+ member(b, [a,a,c,b,a]) fails.
The second clause fails, too.
There are no more clauses for the predicate once(X, [b,a,a,c,b,a]). All of them failed. So the query fails. The primary issue is that \+ X = H (or even X \= H, when X is not instantiated, won't choose a value from the list that is not the same as the value instantiated in H. Its behavior isn't logically what you want.
A more straight-on approach to the predicate would be:
once(X, L) :- % X occurs once in L if...
select(X, L, R), % I can remove X from L giving R, and
\+ member(X, R). % X is not a member of R
The select will query as desired for uninstantiated X, so this will yield:
?- once(c, [b,a,a,c,b,a]).
true ;
false.
?- once(b, [b,a,a,c,b,a]).
false.
?- once(X, [b,a,a,c,b,a]).
X = c ;
false.
As an aside, I'd avoid the predicate name once since it is the name of a built-in predicate in Prolog. But it has no bearing on this particular problem.
Using prolog-dif we can preserve logical-purity!
The following code is based on the previous answer by #lurker, but is logically pure:
onceMember_of(X,Xs) :-
select(X,Xs,Xs0),
maplist(dif(X),Xs0).
Let's look at some queries:
?- onceMember_of(c,[b,a,a,c,b,a]).
true ; % succeeds, but leaves choicepoint
false.
?- onceMember_of(b,[b,a,a,c,b,a]).
false.
?- onceMember_of(X,[b,a,a,c,b,a]).
X = c ;
false.
The code is monotone, so we get logically sound answers for more general uses, too!
?- onceMember_of(X,[A,B,C]).
X = A, dif(A,C), dif(A,B) ;
X = B, dif(B,C), dif(B,A) ;
X = C, dif(C,B), dif(C,A) ;
false.
Let's look at all lists in increasing size:
?- length(Xs,_), onceMember_of(X,Xs).
Xs = [X] ;
Xs = [X,_A], dif(X,_A) ;
Xs = [_A,X], dif(X,_A) ;
Xs = [ X,_A,_B], dif(X,_A), dif(X,_B) ;
Xs = [_A, X,_B], dif(X,_A), dif(X,_B) ;
Xs = [_A,_B, X], dif(X,_A), dif(X,_B) ;
Xs = [ X,_A,_B,_C], dif(X,_A), dif(X,_B), dif(X,_C) ...
At last, let's have the most general query:
?- onceMember_of(X,Xs).
Xs = [X] ;
Xs = [X,_A], dif(X,_A) ;
Xs = [X,_A,_B], dif(X,_A), dif(X,_B) ;
Xs = [X,_A,_B,_C], dif(X,_A), dif(X,_B),dif(X,_C) ...
Edit 2015-05-13
We can do even better by using selectfirst/3, a drop-in replacement of select/3:
onceMember_ofB(X,Xs) :-
selectfirst(X,Xs,Xs0),
maplist(dif(X),Xs0).
Let's run onceMember_of/2 and onceMember_ofB/2 head to head:
?- onceMember_of(c,[b,a,a,c,b,a]).
true ; % succeeds, but leaves choicepoint
false.
?- onceMember_ofB(c,[b,a,a,c,b,a]).
true. % succeeds deterministically
But we can still get better! Consider:
?- onceMember_ofB(X,[A,B,C]).
X = A, dif(A,C), dif(A,B) ;
X = B, dif(B,C), dif(A,B),dif(B,A) ; % 1 redundant constraint
X = C, dif(A,C),dif(C,A), dif(B,C),dif(C,B) ; % 2 redundant constraints
false.
Note the redundant dif/2 constraints? They come from the goal
maplist(dif(X),Xs0) and we can eliminate them, like so:
onceMember_ofC(E,[X|Xs]) :-
if_(E = X, maplist(dif(X),Xs),
onceMember_ofC(E,Xs)).
Let's see if it works!
?- onceMember_ofC(X,[A,B,C]).
X = A, dif(A,C), dif(A,B) ;
X = B, dif(B,C), dif(B,A) ;
X = C, dif(C,B), dif(C,A) ;
false.

Add two more occurrences using prolog

I have a list [a, b, a, a, a, c, c]
and I need to add two more occurrences of each element.
The end result should look like this:
[a, a, a, b, b, b, a, a, a, a, a, c, c, c, c]
If I have an item on the list that is the same as the next item, then it keeps going until there is a new item, when it finds the new item, it adds two occurrences of the previous item then moves on.
This is my code so far, but I can't figure out how to add two...
dbl([], []).
dbl([X], [X,X]).
dbl([H|T], [H,H|T], [H,H|R]) :- dbl(T, R).
Your code looks a bit strange because the last rule takes three parameters. You only call the binary version, so no recursion will ever try to derive it.
You already had a good idea to look at the parts of the list, where elements change. So there are 4 cases:
1) Your list is empty.
2) You have exactly one element.
3) Your list starts with two equal elements.
4) Your list starts with two different elements.
Case 1 is not specified, so you might need to find a sensible choice for that. Case 2 is somehow similar to case 4, since the end of the list can be seen as a change in elements, where you need to append two copies, but then you are done. Case 3 is quite simple, we can just keep the element and recurse on the rest. Case 4 is where you need to insert the two copies again.
This means your code will look something like this:
% Case 1
dbl([],[]).
% Case 2
dbl([X],[X,X,X]).
% Case 3
dbl([X,X|Xs], [X|Ys]) :-
% [...] recursion skipping the leading X
% Case 4
dbl([X,Y|Xs], [X,X,X|Ys]) :-
dif(X,Y),
% [...] we inserted the copies, so recursion on [Y|Xs] and Ys
Case 3 should be easy to finish, we just drop the first X from both lists and recurse on dbl([X|Xs],Ys). Note that we implicitly made the first two elements equal (i.e. we unified them) by writing the same variable twice.
If you look at the head of case 4, you can directly imitate the pattern you described: supposed the list starts with X, then Y and they are different (dif(X,Y)), the X is repeated 3 times instead of just copied and we then continue with the recursion on the rest starting with Y: dbl([Y|Xs],Ys).
So let's try out the predicate:
?- dbl([a,b,a,a,a,c,c],[a,a,a,b,b,b,a,a,a,a,a,c,c,c,c]).
true ;
false.
Our test case is accepted (true) and we don't find more than one solution (false).
Let's see if we find a wrong solution:
?- dif(Xs,[a,a,a,b,b,b,a,a,a,a,a,c,c,c,c]), dbl([a,b,a,a,a,c,c],Xs).
false.
No, that's also good. What happens, if we have variables in our list?
?- dbl([a,X,a],Ys).
X = a,
Ys = [a, a, a, a, a] ;
Ys = [a, a, a, X, X, X, a, a, a],
dif(X, a),
dif(X, a) ;
false.
Either X = a, then Ys is single run of 5 as; or X is not equal to a, then we need to append the copies in all three runs. Looks also fine. (*)
Now lets see, what happens if we only specify the solution:
?- dbl(X,[a,a,a,b,b]).
false.
Right, a list with a run of only two bs can not be a result of our specification. So lets try to add one:
?- dbl(X,[a,a,a,b,b,b]).
X = [a, b] ;
false.
Hooray, it worked! So lets as a last test look what happens, if we just call our predicate with two variables:
?- dbl(Xs,Ys).
Xs = Ys, Ys = [] ;
Xs = [_G15],
Ys = [_G15, _G15, _G15] ;
Xs = [_G15, _G15],
Ys = [_G15, _G15, _G15, _G15] ;
Xs = [_G15, _G15, _G15],
Ys = [_G15, _G15, _G15, _G15, _G15] ;
Xs = [_G15, _G15, _G15, _G15],
Ys = [_G15, _G15, _G15, _G15, _G15, _G15] ;
[...]
It seems we get the correct answers, but we see only cases for a single run. This is a result of prolog's search strategy(which i will not explain in here). But if we look at shorter lists before we generate longer ones, we can see all the solutions:
?- length(Xs,_), dbl(Xs,Ys).
Xs = Ys, Ys = [] ;
Xs = [_G16],
Ys = [_G16, _G16, _G16] ;
Xs = [_G16, _G16],
Ys = [_G16, _G16, _G16, _G16] ;
Xs = [_G86, _G89],
Ys = [_G86, _G86, _G86, _G89, _G89, _G89],
dif(_G86, _G89) ;
Xs = [_G16, _G16, _G16],
Ys = [_G16, _G16, _G16, _G16, _G16] ;
Xs = [_G188, _G188, _G194],
Ys = [_G188, _G188, _G188, _G188, _G194, _G194, _G194],
dif(_G188, _G194) ;
[...]
So it seems we have a working predicate (**), supposed you filled in the missing goals from the text :)
(*) A remark here: this case only works because we are using dif. The first predicates with equality, one usually encounters are =, == and their respective negations \= and \==. The = stands for unifyability (substituting variables in the arguments s.t. they become equal) and the == stands for syntactic equality (terms being exactly equal). E.g.:
?- f(X) = f(a).
X = a.
?- f(X) \= f(a).
false.
?- f(X) == f(a).
false.
?- f(X) \== f(a).
true.
This means, we can make f(X) equal to f(a), if we substitute X by a. This means if we ask if they can not be made equal (\=), we get the answer false. On the other hand, the two terms are not equal, so == returns false, and its negation \== answers true.
What this also means is that X \== Y is always true, so we can not use \== in our code. In contrast to that, dif waits until it can decide wether its arguments are equal or not. If this is still undecided after finding an answer, the "dif(X,a)" statements are printed.
(**) One last remark here: There is also a solution with the if-then-else construct (test -> goals_if_true; goals_if_false, which merges cases 3 and 4. Since i prefer this solution, you might need to look into the other version yourself.
TL;DR:
From a declarative point of view, the code sketched by #lambda.xy.x is perfect.
Its determinacy can be improved without sacrificing logical-purity.
Code variant #0: #lambda.xy.x's code
Here's the code we want to improve:
dbl0([], []).
dbl0([X], [X,X,X]).
dbl0([X,X|Xs], [X|Ys]) :-
dbl0([X|Xs], Ys).
dbl0([X,Y|Xs], [X,X,X|Ys]) :-
dif(X, Y),
dbl0([Y|Xs], Ys).
Consider the following query and the answer SWI-Prolog gives us:
?- dbl0([a],Xs).
Xs = [a,a,a] ;
false.
With ; false the SWI prolog-toplevel
indicates a choicepoint was left when proving the goal.
For the first answer, Prolog did not search the entire proof tree.
Instead, it replied "here's an answer, there may be more".
Then, when asked for more solutions, Prolog traversed the remaining branches of the proof tree but finds no more answers.
In other words: Prolog needs to think twice to prove something we knew all along!
So, how can we give determinacy hints to Prolog?
By utilizing:
control constructs !/0 and / or (->)/2 (potentially impure)
first argument indexing on the principal functor (never impure)
The code presented in the earlier answer by #CapelliC—which is based on !/0, (->)/2, and the meta-logical predicate (\=)/2—runs well if all arguments are sufficiently instantiated. If not, erratic answers may result—as #lambda.xy.x's comment shows.
Code variant #1: indexing
Indexing can improve determinacy without ever rendering the code non-monotonic. While different Prolog processors have distinct advanced indexing capabilities, the "first-argument principal-functor" indexing variant is widely available.
Principal? This is why executing the goal dbl0([a],Xs) leaves a choicepoint behind: Yes, the goal only matches one clause—dbl0([X],[X,X,X]).—but looking no deeper than the principal functor Prolog assumes that any of the last three clauses could eventually get used. Of course, we know better...
To tell Prolog we utilize principal-functor first-argument indexing:
dbl1([], []).
dbl1([E|Es], Xs) :-
dbl1_(Es, Xs, E).
dbl1_([], [E,E,E], E).
dbl1_([E|Es], [E|Xs], E) :-
dbl1_(Es, Xs, E).
dbl1_([E|Es], [E0,E0,E0|Xs], E0) :-
dif(E0, E),
dbl1_(Es, Xs, E).
Better? Somewhat, but determinacy could be better still...
Code variant #2: indexing on reified term equality
To make Prolog see that the two recursive clauses of dbl1_/3 are mutually exclusive (in certain cases), we reify the truth value of
term equality and then index on that value:
This is where reified term equality (=)/3 comes into play:
dbl2([], []).
dbl2([E|Es], Xs) :-
dbl2_(Es, Xs, E).
dbl2_([], [E,E,E], E).
dbl2_([E|Es], Xs, E0) :-
=(E0, E, T),
t_dbl2_(T, Xs, E0, E, Es).
t_dbl2_(true, [E|Xs], _, E, Es) :-
dbl2_(Es, Xs, E).
t_dbl2_(false, [E0,E0,E0|Xs], E0, E, Es) :-
dbl2_(Es, Xs, E).
Sample queries using SWI-Prolog:
?- dbl0([a],Xs).
Xs = [a, a, a] ;
false.
?- dbl1([a],Xs).
Xs = [a, a, a].
?- dbl2([a],Xs).
Xs = [a, a, a].
?- dbl0([a,b,b],Xs).
Xs = [a, a, a, b, b, b, b] ;
false.
?- dbl1([a,b,b],Xs).
Xs = [a, a, a, b, b, b, b] ;
false.
?- dbl2([a,b,b],Xs).
Xs = [a, a, a, b, b, b, b].
To make above code more compact, use control construct if_/3 .
I was just about to throw this version with if_/3 and (=)/3 in the hat when I saw #repeat already suggested it. So this is essentially the more compact version as outlined by #repeat:
list_dbl([],[]).
list_dbl([X],[X,X,X]).
list_dbl([A,B|Xs],DBL) :-
if_(A=B,DBL=[A,B|Ys],DBL=[A,A,A,B|Ys]),
list_dbl([B|Xs],[B|Ys]).
It yields the same results as dbl2/2 by #repeat:
?- list_dbl([a],DBL).
DBL = [a,a,a]
?- list_dbl([a,b,b],DBL).
DBL = [a,a,a,b,b,b,b]
The example query by the OP works as expected:
?- list_dbl([a,b,a,a,a,c,c],DBL).
DBL = [a,a,a,b,b,b,a,a,a,a,a,c,c,c,c]
Plus here are some of the example queries provided by #lambda.xy.x. They yield the same results as #repeat's dbl/2 and #lambda.xy.x's dbl/2:
?- dif(Xs,[a,a,a,b,b,b,a,a,a,a,a,c,c,c,c]), list_dbl([a,b,a,a,a,c,c],Xs).
no
?- list_dbl(X,[a,a,a,b,b]).
no
?- list_dbl(L,[a,a,a,b,b,b]).
L = [a,b] ? ;
no
?- list_dbl(L,DBL).
DBL = L = [] ? ;
DBL = [_A,_A,_A],
L = [_A] ? ;
DBL = [_A,_A,_A,_A],
L = [_A,_A] ? ;
DBL = [_A,_A,_A,_A,_A],
L = [_A,_A,_A] ? ;
...
?- list_dbl([a,X,a],DBL).
DBL = [a,a,a,a,a],
X = a ? ;
DBL = [a,a,a,X,X,X,a,a,a],
dif(X,a),
dif(a,X)
?- length(L,_), list_dbl(L,DBL).
DBL = L = [] ? ;
DBL = [_A,_A,_A],
L = [_A] ? ;
DBL = [_A,_A,_A,_A],
L = [_A,_A] ? ;
DBL = [_A,_A,_A,_B,_B,_B],
L = [_A,_B],
dif(_A,_B) ? ;
DBL = [_A,_A,_A,_A,_A],
L = [_A,_A,_A] ?
dbl([X,Y|T], [X,X,X|R]) :- X \= Y, !, dbl([Y|T], R).
dbl([H|T], R) :-
T = []
-> R = [H,H,H]
; R = [H|Q], dbl(T, Q).
The first clause handles the basic requirement, adding two elements on sequence change.
The second one handles list termination as a sequence change, otherwise, does a plain copy.

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

I'm having an issue with SWI-Prolog's delete/3 predicate.
The easiest way is just a quick example:
?- delete([(1,1),(1,2),(3,2)], (1,_), List).
List = [(1,2),(3,2)].
I would expect (1,2) to also be deleted, since (1,_) unifies with (1,2). The SWIPL help says:
Delete all members of List1 that simultaneously unify with Elem and unify the result with List2.
Why is this and how can I delete everything that unifies with (1,_)?
" Delete all members of List1 that simultaneously unify with Elem and unify the result with List2."
(1,X) first unifies with (1,1). therefore, X is unified with 1 and cannot be unified with 2 to delete (1,2).
so the problem is not that it does not delete all of the members; it's that it doesnt unify simultaneously with (1,2) and (1,1)
(try delete([(1,1),(1,2),(1,1),(3,2)],(1,_),List).
btw, according to the swi-prolog manual:
delete(?List1, ?Elem, ?List2)
Is true when Lis1, with all occurences of Elem deleted results in List2.
also, delete/3 is deprecated:
There are too many ways in which one might want to delete elements from a list to justify the name.
Think of matching (= vs. ==), delete first/all, be deterministic or not.
So the easiest way is to write your own predicate. Something like:
my_delete(Pattern,[Pattern|T],TD):-
my_delete(Pattern,T,TD).
my_delete(Pattern,[H|T],[H|TD]):-
my_delete(Pattern,T,TD).
perhaps?
check exclude/3, include/3, partition/4
Use meta-predicate texclude/3 in combination with the
reified term equality predicate
(=)/3!
First, we try using (=)/3 directly...
?- 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).
Not quite! For our next tries we are going to use lambda expressions.
:- use_module(library(lambda)).
Let's query---once with texclude/3, once with tinclude/3, and once with 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
Alright! Do we get the same solutions if the list items are bound after the texclude/3 call?
?- 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.
Yes! At last, consider the following quite general query:
?- 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).
Note that above goals restrict all list items to have the form (_,_). Thus the following query fails:
?- texclude(\ (K,_)^(K=1), [x,_], _).
false.
This answer tries to generalize the idea presented in previous answer.
Let's define a reified variant of 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
).
The above definition of the reified predicate subsumes_term_t/3 uses free4evrs/1 to ensure that the "generic" term passed to subsumes_term/2 is not instantiated any further.
For SICStus Prolog, we can define it as follows:
:- 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).
Let's put subsumes_term_t/3 to use!
?- 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
What happens if we instantiate variable X in above query sometime after the call to texclude/3?
?- texclude(subsumes_term_t(1-X), [x,1-Y,2-3], Fs), X=something.
! error(uninstantiation_error(something),free4evr/1)