Related
My confusion mainly lies around understanding singleton variables.
I want to implement the predicate noDupl/2 in Prolog. This predicate can be used to identify numbers in a list that appear exactly once, i. e., numbers which are no duplicates. The first argument of noDupl is the list to analyze. The
second argument is the list of numbers which are no duplicates, as described below.
As an example, for the list [2, 0, 3, 2, 1] the result [0, 3, 1] is computed (because 2 is a duplicate).
In my implementation I used the predefined member predicate and used an auxiliary predicate called helper.
I'll explain my logic in pseudocode, so you can help me spot where I went wrong.
First off, If the first element is not a member of the rest of the list, add the first element to the new result List (as it's head).
If the first element is a member of T, call the helper method on the rest of the list, the first element H and the new list.
Helper method, if H is found in the tail, return list without H, i. e., Tail.
noDupl([],[]).
noDupl([H|T],L) :-
\+ member(H,T),
noDupl(T,[H|T]).
noDupl([H|T],L) :-
member(H,T),
helper(T,H,L).
helper([],N,[]).
helper([H|T],H,T). %found place of duplicate & return list without it
helper([H|T],N,L) :-
helper(T,N,[H|T1]).%still couldn't locate the place, so add H to the new List as it's not a duplicate
While I'm writing my code, I'm always having trouble with deciding to choose a new variable or use the one defined in the predicate arguments when it comes to free variables specifically.
Thanks.
Warnings about singleton variables are not the actual problem.
Singleton variables are logical variables that occur once in some Prolog clause (fact or rule). Prolog warns you about these variables if they are named like non-singleton variables, i. e., if their name does not start with a _.
This convention helps avoid typos of the nasty kind—typos which do not cause syntax errors but do change the meaning.
Let's build a canonical solution to your problem.
First, forget about CamelCase and pick a proper predicate name that reflects the relational nature of the problem at hand: how about list_uniques/2?
Then, document cases in which you expect the predicate to give one answer, multiple answers or no answer at all. How?
Not as mere text, but as queries.
Start with the most general query:
?- list_uniques(Xs, Ys).
Add some ground queries:
?- list_uniques([], []).
?- list_uniques([1,2,2,1,3,4], [3,4]).
?- list_uniques([a,b,b,a], []).
And add queries containing variables:
?- list_uniques([n,i,x,o,n], Xs).
?- list_uniques([i,s,p,y,i,s,p,y], Xs).
?- list_uniques([A,B], [X,Y]).
?- list_uniques([A,B,C], [D,E]).
?- list_uniques([A,B,C,D], [X]).
Now let's write some code! Based on library(reif) write:
:- use_module(library(reif)).
list_uniques(Xs, Ys) :-
list_past_uniques(Xs, [], Ys).
list_past_uniques([], _, []). % auxiliary predicate
list_past_uniques([X|Xs], Xs0, Ys) :-
if_((memberd_t(X,Xs) ; memberd_t(X,Xs0)),
Ys = Ys0,
Ys = [X|Ys0]),
list_past_uniques(Xs, [X|Xs0], Ys0).
What's going on?
list_uniques/2 is built upon the helper predicate list_past_uniques/3
At any point, list_past_uniques/3 keeps track of:
all items ahead (Xs) and
all items "behind" (Xs0) some item of the original list X.
If X is a member of either list, then Ys skips X—it's not unique!
Otherwise, X is unique and it occurs in Ys (as its list head).
Let's run some of the above queries using SWI-Prolog 8.0.0:
?- list_uniques(Xs, Ys).
Xs = [], Ys = []
; Xs = [_A], Ys = [_A]
; Xs = [_A,_A], Ys = []
; Xs = [_A,_A,_A], Ys = []
...
?- list_uniques([], []).
true.
?- list_uniques([1,2,2,1,3,4], [3,4]).
true.
?- list_uniques([a,b,b,a], []).
true.
?- list_uniques([1,2,2,1,3,4], Xs).
Xs = [3,4].
?- list_uniques([n,i,x,o,n], Xs).
Xs = [i,x,o].
?- list_uniques([i,s,p,y,i,s,p,y], Xs).
Xs = [].
?- list_uniques([A,B], [X,Y]).
A = X, B = Y, dif(Y,X).
?- list_uniques([A,B,C], [D,E]).
false.
?- list_uniques([A,B,C,D], [X]).
A = B, B = C, D = X, dif(X,C)
; A = B, B = D, C = X, dif(X,D)
; A = C, C = D, B = X, dif(D,X)
; A = X, B = C, C = D, dif(D,X)
; false.
Just like my previous answer, the following answer is based on library(reif)—and uses it in a somewhat more idiomatic way.
:- use_module(library(reif)).
list_uniques([], []).
list_uniques([V|Vs], Xs) :-
tpartition(=(V), Vs, Equals, Difs),
if_(Equals = [], Xs = [V|Xs0], Xs = Xs0),
list_uniques(Difs, Xs0).
While this code does not improve upon my previous one regarding efficiency / complexity, it is arguably more readable (fewer arguments in the recursion).
In this solution a slightly modified version of tpartition is used to have more control over what happens when an item passes the condition (or not):
tpartition_p(P_2, OnTrue_5, OnFalse_5, OnEnd_4, InitialTrue, InitialFalse, Xs, RTrue, RFalse) :-
i_tpartition_p(Xs, P_2, OnTrue_5, OnFalse_5, OnEnd_4, InitialTrue, InitialFalse, RTrue, RFalse).
i_tpartition_p([], _P_2, _OnTrue_5, _OnFalse_5, OnEnd_4, CurrentTrue, CurrentFalse, RTrue, RFalse):-
call(OnEnd_4, CurrentTrue, CurrentFalse, RTrue, RFalse).
i_tpartition_p([X|Xs], P_2, OnTrue_5, OnFalse_5, OnEnd_4, CurrentTrue, CurrentFalse, RTrue, RFalse):-
if_( call(P_2, X)
, call(OnTrue_5, X, CurrentTrue, CurrentFalse, NCurrentTrue, NCurrentFalse)
, call(OnFalse_5, X, CurrentTrue, CurrentFalse, NCurrentTrue, NCurrentFalse) ),
i_tpartition_p(Xs, P_2, OnTrue_5, OnFalse_5, OnEnd_4, NCurrentTrue, NCurrentFalse, RTrue, RFalse).
InitialTrue/InitialFalse and RTrue/RFalse contains the desired initial and final state, procedures OnTrue_5 and OnFalse_5 manage state transition after testing the condition P_2 on each item and OnEnd_4 manages the last transition.
With the following code for list_uniques/2:
list_uniques([], []).
list_uniques([V|Vs], Xs) :-
tpartition_p(=(V), on_true, on_false, on_end, false, Difs, Vs, HasDuplicates, []),
if_(=(HasDuplicates), Xs=Xs0, Xs = [V|Xs0]),
list_uniques(Difs, Xs0).
on_true(_, _, Difs, true, Difs).
on_false(X, HasDuplicates, [X|Xs], HasDuplicates, Xs).
on_end(HasDuplicates, Difs, HasDuplicates, Difs).
When the item passes the filter (its a duplicate) we just mark that the list has duplicates and skip the item, otherwise the item is kept for further processing.
This answer goes similar ways as this previous answer by #gusbro.
However, it does not propose a somewhat baroque version of tpartition/4, but instead an augmented, but hopefully leaner, version of tfilter/3 called tfilter_t/4 which can be defined like so:
tfilter_t(C_2, Es, Fs, T) :-
i_tfilter_t(Es, C_2, Fs, T).
i_tfilter_t([], _, [], true).
i_tfilter_t([E|Es], C_2, Fs0, T) :-
if_(call(C_2,E),
( Fs0 = [E|Fs], i_tfilter_t(Es,C_2,Fs,T) ),
( Fs0 = Fs, T = false, tfilter(C_2,Es,Fs) )).
Adapting list_uniques/2 is straightforward:
list_uniques([], []).
list_uniques([V|Vs], Xs) :-
if_(tfilter_t(dif(V),Vs,Difs), Xs = [V|Xs0], Xs = Xs0),
list_uniques(Difs, Xs0).
Save scrollbars. Stay lean! Use filter_t/4.
You have problems already in the first predicate, noDupl/2.
The first clause, noDupl([], []). looks fine.
The second clause is wrong.
noDupl([H|T],L):-
\+member(H,T),
noDupl(T,[H|T]).
What does that really mean I leave as an exercise to you. If you want, however, to add H to the result, you would write it like this:
noDupl([H|T], [H|L]) :-
\+ member(H, T),
noDupl(T, L).
Please look carefully at this and try to understand. The H is added to the result by unifying the result (the second argument in the head) to a list with H as the head and the variable L as the tail. The singleton variable L in your definition is a singleton because there is a mistake in your definition, namely, you do nothing at all with it.
The last clause has a different kind of problem. You try to clean the rest of the list from this one element, but you never return to the original task of getting rid of all duplicates. It could be fixed like this:
noDupl([H|T], L) :-
member(H, T),
helper(T, H, T0),
noDupl(T0, L).
Your helper/3 cleans the rest of the original list from the duplicate, unifying the result with T0, then uses this clean list to continue removing duplicates.
Now on to your helper. The first clause seems fine but has a singleton variable. This is a valid case where you don't want to do anything with this argument, so you "declare" it unused for example like this:
helper([], _, []).
The second clause is problematic because it removes a single occurrence. What should happen if you call:
?- helper([1,2,3,2], 2, L).
The last clause also has a problem. Just because you use different names for two variables, this doesn't make them different. To fix these two clauses, you can for example do:
helper([H|T], H, L) :-
helper(T, H, L).
helper([H|T], X, [H|L]) :-
dif(H, X),
helper(T, X, L).
These are the minimal corrections that will give you an answer when the first argument of noDupl/2 is ground. You could do this check this by renaming noDupl/2 to noDupl_ground/2 and defining noDupl/2 as:
noDupl(L, R) :-
must_be(ground, L),
noDupl_ground(L, R).
Try to see what you get for different queries with the current naive implementation and ask if you have further questions. It is still full of problems, but it really depends on how you will use it and what you want out of the answer.
My aim is writing a predicate filter/3. With input list [bar(a,12),bar(b,12),bar(c,13)] and filter criteria bar(A,12) the expected output is [bar(a,12),bar(b,12)].
The code below works but what is the difference between writing \+ \+ Filter = X and Filter = X (for me it is same). I wrote down the program by using 2 versions and it gave the same correct result. But I am sure that they are different?!
filter([],_,[]).
filter([X|XS],Filter,[X|ZS]) :-
\+ \+ Filter=X,
!,
filter(XS,Filter,ZS).
filter([_|XS],Filter,ZS) :-
filter(XS,Filter,ZS).
EDIT:
#lurker you are right, they do not give the same result. ( it was my mistake)
----using \+ \+ Filter = X -----
?- filter([foo(a,12),foo(c,12),foo(b,13)],foo(A,12),Res).
Res = [foo(a, 12), foo(c, 12)].
----using Filter = X -----
?- filter([foo(a,12),foo(c,12),foo(b,13)],foo(A,12),Res).
A = a,
Res = [foo(a, 12)].
?- filter([foo(a,12),foo(a,12),foo(b,13)],foo(A,12),Res).
A = a,
Res = [foo(a, 12), foo(a, 12)].
TL;DR
?- tfilter(\bar(_,S)^(S=12), Xs, Ys).
Now, step-by-step:
There are several issues with your program. The biggest is the actual problem statement which leaves several things open. For example, I assume that you expect that all elements are of the form bar(X, N) and you want to select those with N = 12. What you have implemented is slightly different:
?- filter([bar(a,12),bar(b,12),bar(c,13)], bar(_,12), []).
true.
This anomaly is due to your specific use of the cut. As you can see from the other answers, many versions avoid it. Cut is extremely difficult to use without any surprising effects. #CapelliC's version with cut actually avoids this one problem, but this is a very tricky business.
A further anomaly concerns the way how you might want to generalize your query. What about asking:
?- filter([X], bar(_,12), Xs).
What should a correct answer be? Should Xs include X or not? After all, instances of this query produce different results, too! I will show two of them by adding the goals X = bar(a,12) and X = bar(a,13) in front.
?- X = bar(a,12), filter([X], bar(_,12), Xs).
Xs = [bar(a,12)].
?- X = bar(a,13), filter([X], bar(_,12), Xs).
Xs = [].
So in one case we have an element, and in the other we have not. The general query should thus consequently produce two answers.
Here is an approach which does not have such problems:
State the positive selection criteria.
Let's use a separate predicate for the selection criteria, and call it _true:
snd_bar_true(N, bar(_,N)).
State the negative selection criteria.
snd_bar_false(N, bar(_,S)) :-
dif(N, S).
Now, with both, we can write a clean and correct filter program. Note that N is now just the second argument.
filter([], _N, []).
filter([X|Xs], N, [X|Ys]) :-
snd_bar_true(N, X),
filter(Xs, N, Ys).
filter([X|Xs], N, Ys) :-
snd_bar_false(N, X),
filter(Xs, N, Ys).
?- filter([X], 12, Xs).
X = bar(_A, 12), Xs = [bar(_A, 12)]
; X = bar(_A, _B), Xs = [], dif(_B, 12).
So we get two answers: One selecting the element X provided it is of the form bar(_,12). And the other one, which does not select the element, but ensures that the second element is not 12.
While these answers are all perfect and fine, I'm not very happy with it: It is correct but soo verbose. Here is a way to make it more compact.
Merge the criteria into one "reified" definition
snd_bar_t(N, bar(_,N), true).
snd_bar_t(N, bar(_,S), false) :-
dif(S,N).
There is a more compact and efficient way to express this using (=)/3
snd_bar_t(N, bar(_,S), T) :-
=(S, N, T).
=(X, X, true).
=(X, Y, false) :-
dif(X,Y).
This (=)/3 can be more efficiently implemented as:
=(X, Y, T) :-
( X == Y -> T = true
; X \= Y -> T = false
; T = true, X = Y
; T = false,
dif(X, Y)
).
Now, we can use the generic tfilter/3:
filter(Xs, N, Ys) :-
tfilter(snd_bar_t(N), Xs, Ys).
And then, we can use library(lambda) to avoid the auxiliary definition:
filter(Xs, N, Ys) :-
tfilter(N+\bar(_,S)^(S = N), Xs, Ys).
Note that this (S = N) is not what you probably think! It is effectively not simple equality, but actually, the reified version of it! So it will be called like: call((S = 12), T) and thus =(S, 12, T).
Double negation it's an old 'trick of the trade' often used while writing metainterpreters.
Since variables instantiation due to unification it's undone on backtracking, it has a procedural only semantic of "prove a goal without binding its variables", whatever the meaning of such phrase could be.
1 ?- filter([bar(a,12),bar(b,12),bar(c,13)],bar(_,12),L).
L = [bar(a, 12), bar(b, 12)].
If you comment out (i.e. remove) the double negation, you observe the undue instantiation effect: X has been bound to bar(a,12), and then cannot be matched to bar(b,12).
2 ?- filter([bar(a,12),bar(b,12),bar(c,13)],bar(_,12),L).
L = [bar(a, 12)].
edit for the simple case at hand, an alternative implementation of filter/3 could be
filter([],_,[]).
filter([X|XS],Filter,ZS):-
X \= Filter, !, filter(XS, Filter, ZS).
filter([X|XS],Filter,[X|ZS]):-
filter(XS, Filter, ZS).
or, better
filter([],_,[]).
filter([X|XS],Filter,R):-
(X \= Filter -> R = ZS ; R = [X|ZS]), filter(XS, Filter, ZS).
but if your system implements subsumes_term/2, #Boris' answer is to be preferred
The answer by #CapelliC answers your question.
There is another standard predicate, subsumes_term/2, which can be used to achieve the same effect as the double negation:
filter0([], _, []).
filter0([X|Xs], T, Ys) :-
\+ subsumes_term(T, X),
filter0(Xs, T, Ys).
filter0([X|Xs], T, [X|Ys]) :-
subsumes_term(T, X),
filter0(Xs, T, Ys).
As to how to do the iteration over all elements, instead of a cut, prefer a conditional:
filter1([], _, []).
filter1([X|Xs], T, R) :-
( subsumes_term(T, X)
-> R = [X|Ys]
; R = Ys
),
filter1(Xs, T, Ys).
And if you write this, you can as well use include/3 (which, by the way, is literally a "filter" predicate):
filter(List, Term, Filtered) :-
include(subsumes_term(Term), List, Filtered).
I've started to learn Prolog recently and I can't solve how to make union of three lists.
I was able to make union of 2 lists :
%element
element(X,[X|_]).
element(X,[_|Y]):-
element(X,Y).
%union
union([],M,M).
union([X|Y],L,S) :- element(X,L),union(Y,L,S).
union([X|Y],L,[X|S]) :- (not(element(X,L))),union(Y,L,S).
can anybody help me please ?
union(A, B, C, U) :-
union(A, B, V),
union(C, V, U).
Your definition of union/3 can be improved by replacing
... not(element(X,L)), ...
by
... maplist(dif(X),L), ...
or
... non_member(X, L), ....
non_member(_X, []).
non_member(X, [E|Es]) :-
dif(X, E),
non_member(X, Es).
Here is a case where the difference shows:
?- union([A],[B],[C,D]).
A = C, B = D, dif(C, D).
How must [A] and [B] look like such that their union contains 2 elements?
The answer is: they must be different.
Your original version fails for this query, yet, it succeeds for a specialized instance like:
?- A = 1, B = 2, union([A],[B],[C,D]).
So it succeeds for this, but fails for a generalization of it. Therefore it is not a pure, logical relation.
So is everything fine and perfect with dif/2? Unfortunately not. #TudorBerariu has good reason to go for a cut, since it reflects some of the intention we have about the relation. The cut effectively reflects two key intentions
that the alternative of not being a member is now excluded, which is true for certain modes, like Arg1 and Arg2 being both sufficiently instantiated terms. A safe approximation would be ground terms.
that there is no need to look at further elements in the list Arg2, which again is only true if Arg1 and Arg2 are sufficiently instantiated.
Problems only show when terms are not sufficiently instantiated..
The drawback of OP's definition and the one above, is that both are unnecessarily too general which can be observed with repeated elements in Arg2:
?- union([a,a],[a,a],Zs).
Zs = [a, a]
; Zs = [a, a]
; Zs = [a, a]
; Zs = [a, a]
; false.
In fact, we get |Arg2||Arg1|-1 redundant answers. So the cut had some good reason to be there.
Another reason why union/3 as it stands is not very efficient is that for the (intended) ground case it leaves open unnecessary choice points. Again, #TudorBerariu's solution does not have this problem:
?- union([a],[a],Zs).
Zs = [a]
; false. % <--- Prolog does not know that there is nothing left
Eliminating redundancy
The actual culprit for that many redundant answers is the first rule. element(a,[a,a]) (commonly called member/2) will succeed twice.
union([X|Y],L,S) :- element(X,L), union(Y,L,S).
^^^^^^^^^^^^
Here is an improved definition:
memberd(X, [X|_Ys]).
memberd(X, [Y|Ys]) :-
dif(X,Y), % new!
memberd(X, Ys).
The recursive rule, reading it right-to-left, reads as follows:
Assume memberd(X, Ys) is true already for some X and Ys. Given that, and given that we have a fitting Y which is different from X. Thenwe can conclude that also memberd(X, [Y|Ys]) is true.
So this has eliminated the redundant solutions. But our definition is still not very efficient: it still has to visit Arg2 twice for each element, and then it is unable to conclude that no alternatives are left. In any case: resist to place a cut to remove this.
Introducing determinism via reification.
Compare the definitions of memberd/2 and non_member/2. Although they describe "the opposite" of each other, they look very similar:
non_member(_X, []).
non_member(X, [Y|Ys]) :-
dif(X,Y),
non_member(X, Ys).
memberd(X, [X|_Ys]).
memberd(X, [Y|Ys]) :-
dif(X,Y),
memberd(X, Ys).
The recursive rule is the same! Only the fact is a different one. Let's merge them into one definition - with an additional argument telling whether we mean memberd (true) or non_member (false):
memberd_t(_X, [], false).
memberd_t(X, [X|_Ys], true).
memberd_t(X, [Y|Ys], Truth) :-
dif(X, Y),
memberd_t(X, Ys, Truth).
Now, our definition gets a bit more compact:
unionp([], Ys, Ys).
unionp([X|Xs], Ys, Zs0) :-
if_( memberd_t(X, Ys), Zs0 = Zs, Zs0 = [X|Zs] ),
unionp(Xs, Ys, Zs).
memberd_t(_X, [], false). % see below
memberd_t(X, [Y|Ys], Truth) :-
if_( X = Y, Truth=true, memberd_t(X, Ys, Truth) ).
Note the difference between if_(If_1, Then_0, Else_0) and the if-then-else control construct ( If_0 -> Then_0 ; Else_0 ). While If_1 may succeed several times with different truth values (that is, it can be both true and false), the control construct makes If_0 succeed only once for being true only.
if_(If_1, Then_0, Else_0) :-
call(If_1, T),
( T == true -> call(Then_0)
; T == false -> call(Else_0)
; nonvar(T) -> throw(error(type_error(boolean,T),_))
; /* var(T) */ throw(error(instantiation_error,_))
).
=(X, Y, T) :-
( X == Y -> T = true
; X \= Y -> T = false
; T = true, X = Y
; T = false,
dif(X, Y) % ISO extension
% throw(error(instantiation_error,_)) % ISO strict
).
equal_t(X, Y, T) :-
=(X, Y, T).
To ensure that memberd_t/3 will always profit from first-argument indexing, rather use the following definition (thanks to #WillNess):
memberd_t(E, Xs, T) :-
i_memberd_t(Xs, E, T).
i_memberd_t([], _E, false).
i_memberd_t([X|Xs], E, T) :-
if_( X = E, T = true, i_memberd_t(Xs, E, T) ).
You can make the union of the first two lists and then the union between that result and the third:
union(L1, L2, L3, U):-union(L1, L2, U12), union(U12, L3, U).
You can improve union/3 with a cut operator:
union([],M,M).
union([X|Y],L,S) :- element(X,L), !, union(Y,L,S).
union([X|Y],L,[X|S]) :- union(Y,L,S).
Using only predicates with an extra argument such as memberd_t/3 leads only to weak reification. For strong reification we also need to generate constraints. Strong reification is a further approach to eliminate non-determinism.
But strong reification is difficult, a possible way to archive this is to use a CLP(*) instance which has also reified logical operators. Here is an example if using CLP(FD) for the union problem. Unfortunately this covers only the domain Z:
Strong Reification Code:
member(_, [], 0).
member(X, [Y|Z], B) :-
(X #= Y) #\/ C #<==> B,
member(X, Z, C).
union([], X, X).
union([X|Y], Z, T) :-
freeze(B, (B==1 -> T=R; T=[X|R])),
member(X, Z, B),
union(Y, Z, R).
The above doesn't suffer from unnecessary choice points. Here are some example that show that this isn't happening anymore:
Running a Ground Example:
?- union([1,2],[2,3],X).
X = [1, 2, 3].
Also the above example even doesn't create choice points, if we use variables somewhere. But we might see a lot of constraints:
Running a Non-Ground Example:
?- union([1,X],[X,3],Y).
X#=3#<==>_G316,
1#=X#<==>_G322,
_G316 in 0..1,
freeze(_G322, (_G322==1->Y=[X, 3];Y=[1, X, 3])),
_G322 in 0..1.
?- union([1,X],[X,3],Y), X=2.
X = 2,
Y = [1, 2, 3].
Since we didn't formulate some input invariants, the interpreter isn't able to see that producing constraints in the above case doesn't make any sense. We can use the all_different/1 constraint to help the interpreter a little bit:
Providing Invariants:
?- all_different([1,X]), all_different([X,3]), union([1,X],[X,3],Y).
Y = [1, X, 3],
X in inf..0\/2\/4..sup,
all_different([X, 3]),
all_different([1, X]).
But we shouldn't expect too much from this singular example. Since the CLP(FD) and the freeze/2 is only an incomplete decision procedure for propositions and Z equations, the approach might not work as smooth as here in every situation.
Bye
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.
I am completely new to Prolog and trying some exercises. One of them is:
Write a predicate set(InList,OutList)
which takes as input an arbitrary
list, and returns a list in which each
element of the input list appears only
once.
Here is my solution:
member(X,[X|_]).
member(X,[_|T]) :- member(X,T).
set([],[]).
set([H|T],[H|Out]) :-
not(member(H,T)),
set(T,Out).
set([H|T],Out) :-
member(H,T),
set(T,Out).
I'm not allowed to use any of built-in predicates (It would be better even do not use not/1). The problem is, that set/2 gives multiple same solutions. The more repetitions in the input list, the more solutions will result. What am I doing wrong? Thanks in advance.
You are getting multiple solutions due to Prolog's backtracking. Technically, each solution provided is correct, which is why it is being generated. If you want just one solution to be generated, you are going to have to stop backtracking at some point. This is what the Prolog cut is used for. You might find that reading up on that will help you with this problem.
Update: Right. Your member() predicate is evaluating as true in several different ways if the first variable is in multiple positions in the second variable.
I've used the name mymember() for this predicate, so as not to conflict with GNU Prolog's builtin member() predicate. My knowledge base now looks like this:
mymember(X,[X|_]).
mymember(X,[_|T]) :- mymember(X,T).
not(A) :- \+ call(A).
set([],[]).
set([H|T],[H|Out]) :-
not(mymember(H,T)),
set(T,Out).
set([H|T],Out) :-
mymember(H,T),
set(T,Out).
So, mymember(1, [1, 1, 1]). evaluates as true in three different ways:
| ?- mymember(1, [1, 1, 1]).
true ? a
true
true
no
If you want to have only one answer, you're going to have to use a cut. Changing the first definition of mymember() to this:
mymember(X,[X|_]) :- !.
Solves your problem.
Furthermore, you can avoid not() altogether, if you wish, by defining a notamember() predicate yourself. The choice is yours.
A simpler (and likely faster) solution is to use library predicate sort/2 which remove duplicates in O(n log n). Definitely works in Yap prolog and SWIPL
You are on the right track... Stay pure---it's easy!
Use reified equality predicates =/3 and dif/3 in combination with if_/3, as implemented in Prolog union for A U B U C:
=(X, Y, R) :- X == Y, !, R = true.
=(X, Y, R) :- ?=(X, Y), !, R = false. % syntactically different
=(X, Y, R) :- X \= Y, !, R = false. % semantically different
=(X, Y, R) :- R == true, !, X = Y.
=(X, X, true).
=(X, Y, false) :-
dif(X, Y).
% dif/3 is defined like (=)/3
dif(X, Y, R) :- X == Y, !, R = false.
dif(X, Y, R) :- ?=(X, Y), !, R = true. % syntactically different
dif(X, Y, R) :- X \= Y, !, R = true. % semantically different
dif(X, Y, R) :- R == true, !, X \= Y.
dif(X, Y, true) :- % succeed first!
dif(X, Y).
dif(X, X, false).
if_(C_1, Then_0, Else_0) :-
call(C_1, Truth),
functor(Truth,_,0), % safety check
( Truth == true -> Then_0 ; Truth == false, Else_0 ).
Based on these predicates we build a reified membership predicate list_item_isMember/3. It is semantically equivalent with memberd_truth/3 by #false. We rearrange the argument order so the list is the 1st argument. This enables first-argument indexing which prevents leaving useless choice-points behind as memberd_truth/3 would create.
list_item_isMember([],_,false).
list_item_isMember([X|Xs],E,Truth) :-
if_(E = X, Truth = true, list_item_isMember(Xs,E,Truth)).
list_set([],[]).
list_set([X|Xs],Ys) :-
if_(list_item_isMember(Xs,X), Ys = Ys0, Ys = [X|Ys0]),
list_set(Xs,Ys0).
A simple query shows that all redundant answers have been eliminated and that the goal succeeds without leaving any choice-points behind:
?- list_set([1,2,3,4,1,2,3,4,1,2,3,1,2,1],Xs).
Xs = [4,3,2,1]. % succeeds deterministically
Edit 2015-04-23
I was inspired by #Ludwig's answer of set/2, which goes like this:
set([],[]).
set([H|T],[H|T1]) :- subtract(T,[H],T2), set(T2,T1).
SWI-Prolog's builtin predicate subtract/3 can be non-monotone, which may restrict its use. list_item_subtracted/3 is a monotone variant of it:
list_item_subtracted([],_,[]).
list_item_subtracted([A|As],E,Bs1) :-
if_(dif(A,E), Bs1 = [A|Bs], Bs = Bs1),
list_item_subtracted(As,E,Bs).
list_setB/2 is like set/2, but is based on list_item_subtracted/3---not subtract/3:
list_setB([],[]).
list_setB([X|Xs1],[X|Ys]) :-
list_item_subtracted(Xs1,X,Xs),
list_setB(Xs,Ys).
The following queries compare list_set/2 and list_setB/2:
?- list_set([1,2,3,4,1,2,3,4,1,2,3,1,2,1], Xs).
Xs = [4,3,2,1]. % succeeds deterministically
?- list_setB([1,2,3,4,1,2,3,4,1,2,3,1,2,1],Xs).
Xs = [1,2,3,4]. % succeeds deterministically
?- list_set(Xs,[a,b]).
Xs = [a,b]
; Xs = [a,b,b]
; Xs = [a,b,b,b]
... % does not terminate universally
?- list_setB(Xs,[a,b]).
Xs = [a,b]
; Xs = [a,b,b]
; Xs = [a,b,b,b]
... % does not terminate universally
I think that a better way to do this would be:
set([], []).
set([H|T], [H|T1]) :- subtract(T, [H], T2), set(T2, T1).
So, for example ?- set([1,4,1,1,3,4],S) give you as output:
S = [1, 4, 3]
Adding my answer to this old thread:
notmember(_,[]).
notmember(X,[H|T]):-X\=H,notmember(X,T).
set([],[]).
set([H|T],S):-set(T,S),member(H,S).
set([H|T],[H|S]):-set(T,S),not(member(H,S)).
The only virtue of this solution is that it uses only those predicates that have been introduced by the point where this exercise appears in the original text.
This works without cut, but it needs more lines and another argument.
If I change the [H2|T2] to S on line three, it will produce multiple results. I don't understand why.
setb([],[],_).
setb([H|T],[H|T2],A) :- not(member(H,A)),setb(T,T2,[H|A]).
setb([H|T],[H2|T2],A) :- member(H,A),setb(T,[H2|T2],A).
setb([H|T],[],A) :- member(H,A),setb(T,[],A).
set(L,S) :- setb(L,S,[]).
You just have to stop the backtracking of Prolog.
enter code here
member(X,[X|_]):- !.
member(X,[_|T]) :- member(X,T).
set([],[]).
set([H|T],[H|Out]) :-
not(member(H,T)),
!,
set(T,Out).
set([H|T],Out) :-
member(H,T),
set(T,Out).
Using the support function mymember of Tim, you can do this if the order of elements in the set isn't important:
mymember(X,[X|_]).
mymember(X,[_|T]) :- mymember(X,T).
mkset([],[]).
mkset([T|C], S) :- mymember(T,C),!, mkset(C,S).
mkset([T|C], S) :- mkset(C,Z), S=[T|Z].
So, for example ?- mkset([1,4,1,1,3,4],S) give you as output:
S = [1, 3, 4]
but, if you want a set with the elements ordered like in the list you can use:
mkset2([],[], _).
mkset2([T|C], S, D) :- mkset2(C,Z,[T|D]), ((mymember(T,D), S=Z,!) ; S=[T|Z]).
mkset(L, S) :- mkset2(L,S,[]).
This solution, with the same input of the previous example, give to you:
S = [1, 4, 3]
This time the elements are in the same order as they appear in the input list.
/* Remove duplicates from a list without accumulator */
our_member(A,[A|Rest]).
our_member(A, [_|Rest]):-
our_member(A, Rest).
remove_dup([],[]):-!.
remove_dup([X|Rest],L):-
our_member(X,Rest),!,
remove_dup(Rest,L).
remove_dup([X|Rest],[X|L]):-
remove_dup(Rest,L).