The aim is to implement the predicate noDupl/2.
The first argument of this predicate is the list to analyze and second argument is the list of numbers which are no duplicate.
I could not understand code below and when I compiled it, it gave an error message that contained is undefined procedure, however as a hint it is written that we can use as predefined predicate contained and notContained. I think I need to define contained and notContained.
noDupl(XS, Res):-
help( XS, [],Res).
help([],_,[]).
help([X|XS],Seen,[X|Res]):-
notContained(X,XS),
notContained(X,Seen),
help(XS, [X|Seen], Res).
help([X|XS],Seen,Res):-
contained(X,Seen),
help(XS, Seen, Res).
help([X|XS],Seen,Res):-
contained(X,XS),
help(XS, [X|Seen], Res).
Could someone please explain me the problem.
The missing definitions might be:
contained(X,[X|_]).
contained(X,[E|Es]) :-
dif(X, E),
contained(X, Es).
notContained(_X, []).
notContained(X, [E|Es]) :-
dif(X, E),
notContained(X, Es).
(I like to call these relations rather memberd/2 and non_member/2.)
The definition you gave extends the relation with an extra argument for the elements considered so far.
To understand the meaning of each clause, read each right-to-left in the direction of the arrow (the :- is a 1970's ASCII-fication of ←). Let's take the first rule:
Provided, that X is not an element of XS, and
provided, that X is not an element of Seen, and
provided, that help(X, [X|Seen], Res) is true,
then also help([X|XS],Seen,[X|Res]) is true.
In other words, if X is neither in the list of visited elements Seen nor in the elements yet to be visited XS, then it does not possess a duplicate.
What is a bit difficult to understand is whether or not the clauses you gave are mutually exclusive - this is, strictly speaking, not your concern, as long as you are only interested in declarative properties, but it is a good idea to avoid such redundancies.
Here is a case, where such redundancy shows:
?- noDupl([a,a,a],U).
U = []
; U = []
; false.
Ideally, the system would give one determinate answer:
?- noDupl([a,a,a], U).
U = [].
Personally, I do not like a lot to split things into too many cases. Essentially, we could have two: it is a duplicate, and it is none.
It is possible to provide a definition that is correct and still fully determinate for the cases where determinism is possible - such as when the first argument is "sufficiently instantiated" (which includes a ground list). Let's see if there are some answers into that direction.
I've annotated your code for you:
noDupl( XS , Res ) :- % Res is the [unique] set of element from the bag XS
help( XS, [],Res) % if invoking the helper succeeds.
. %
help( [] , _ , [] ) . % the empty list is unique.
help( [X|XS] , Seen , [X|Res] ) :- % A non-empty list is unique, if...
notContained(X,XS), % - its head (X) is not contained in its tail (XS), and
notContained(X,Seen), % - X has not already been seen, and
help(XS, [X|Seen], Res). % - the remainder of the list is unique.
help( [X|XS] , Seen , Res ) :- % otherwise...
contained(X,Seen) , % - if X has been seen,
help(XS, Seen, Res). % - we discard it and recurse down on the tail.
help([X|XS],Seen,Res):- % otherwise...
contained(X,XS), % - if X is in the tail of the source list,
help(XS, [X|Seen], Res). % - we discard it (but add it to 'seen').
Your contained/2 and notContained/2` predicates might be defined as this:
contained( X , [X|_] ) :- ! .
contained( X , [Y|Ys] ) :- X \= Y , contained( X , Ys ) .
not_contained( _ , [] ) .
not_contained( X , [Y|Ys] ) :- X \= Y , not_contained(X,Ys) .
Now, I may be missing something in your code, but there's an awful lot of redundancy in it. You could simply write something like this (using the built-ins member/2 and reverse/2):
no_dupes( List , Unique ) :- no_dupes( Bag , [] , Set ) .
no_dupes( [] , V , S ) . % if we've exhausted the bag, the list of visited items is our set (in reverse order of the source)
reverse(V,S) % - reverset it
. % - to put our set in source order
no_dupes( [X|Xs] , V , S ) :- % otherwise ...
( member(X,V) -> % - if X is already in the set,
V1 = V % - then we discard X
; V1 = [X|V] % - else we add X to the set
) , % And...
no_dupes( Xs , V1 , S ) % we recurse down on the remainder
. % Easy!
Can this be done in a pure and efficient way?
Yes, by using
tpartition/4 and (=)/3 like so:
dups_gone([] ,[]).
dups_gone([X|Xs],Zs0) :-
tpartition(=(X),Xs,Ts,Fs),
if_(Ts=[], Zs0=[X|Zs], Zs0=Zs),
dups_gone(Fs,Zs).
Some sample ground queries (all of which succeed deterministically):
?- dups_gone([a,a,a],Xs).
Xs = [].
?- dups_gone([a,b,c],Xs).
Xs = [a, b, c].
?- dups_gone([a,b,c,b],Xs).
Xs = [a, c].
?- dups_gone([a,b,c,b,a],Xs).
Xs = [c].
?- dups_gone([a,b,c,b,a,a,a],Xs).
Xs = [c].
?- dups_gone([a,b,c,b,a,a,a,c],Xs).
Xs = [].
This also works with more general queries. Consider:
?- length(Xs,N), dups_gone(Xs,Zs).
N = 0, Xs = [], Zs = []
; N = 1, Xs = [_A], Zs = [_A]
; N = 2, Xs = [_A,_A], Zs = []
; N = 2, Xs = [_A,_B], Zs = [_A,_B], dif(_A,_B)
; N = 3, Xs = [_A,_A,_A], Zs = []
; N = 3, Xs = [_A,_A,_B], Zs = [_B], dif(_A,_B)
; N = 3, Xs = [_A,_B,_A], Zs = [_B], dif(_A,_B)
; N = 3, Xs = [_B,_A,_A], Zs = [_B], dif(_A,_B), dif(_A,_B)
; N = 3, Xs = [_A,_B,_C], Zs = [_A,_B,_C], dif(_A,_B), dif(_A,_C), dif(_B,_C)
; N = 4, Xs = [_A,_A,_A,_A], Zs = []
...
Related
I am still learning Prolog and I came across this little snippet of code that I don't quite know if I have understood correctly.
Code:
% Takes the spiders friends and returns a list with persons who don't know each other.
getConspirators( [], Res, Res).
getConspirators( [H|T], CConspirators, Res):-
append( [H|T], CConspirators, PK),
knowsAtleastOne( PK),
% Gets all the friends of the possible conspirator H.
allFriends( H, PFriends),
subtract( T, PFriends, Pprim),
getConspirators( Pprim, [H|CConspirators], Res).
getConspirators( [_|T], CConspirators, Res) :-
getConspirators( T, CConspirators, Res).
% Checks if any person Y or Y's friends know anybody in PK.
knowsAtleastOne( PK):-
forall( person(Y), (memberchk(Y,PK) ; friendCons(Y,PK)) ).
% Checks if a person X's friends know any of the conspirators.
friendCons( X, Conspirators):-
friend( X, Y),
memberchk( Y, Conspirators),
!.
(this is NOT the whole program, just a small snippet of it)
I am not sure if I have understood the getConspirators( [H|T], CConspirators, Res) :- and the getConspirators( [_|T], CConspirators, Res) :- parts of the
getConspirators predicate. They look almost the same! Now, I do know that the "_" symbol means "literally any value" (AKA Prolog doesn't care about what value it is). But how does Prolog know which case to pick when running through the code? My theory is that Prolog runs the getConspirators( [_|T], CConspirators, Res) :- case if and only if the getConspirators( [H|T], CConspirators, Res) :- case fails (returns false) somewhere along the way. Have I understood this correctly?
There are three elements in play here: backtracking, unification and the list notation. I'll explain the three with a simpler example:
moon(europa).
moon(ganymede).
planet(jupiter).
planet(saturn).
We know that Europa and Ganymede are two moons (of Jupiter) and that Jupiter and Saturn are planets. When we query what planets are known, we write:
?- planet(X).
X = jupiter ; % type ; for the next answer
X = saturn. % there's no more answer, hence .
Unification happens when prolog looks for a rule head which fits to the query where the variables are substituted accordingly. For instance, there is no substitution that makes moon(X) = planet(Y) equal, but there is one for planet(jupiter) = planet(X), namely X=jupiter. That's how you obtain the first solution. For the second solution, Prolog needs to unifywith the second rule head, namely planet(saturn) = planet(X). Because this is done after the first option is completely enumerated, we call this backtracking.
Now we can focus on (linked) lists. A list is either empty ([]) or it has a first element X prepended to a tail list Xs ([X|Xs]). Prolog has also a nicer notation for the list [X | [Y | [] ]], namely [X,Y]. Internally they are the same. When we now want to collect a list of astral objects, we can formulate the following three rules:
astral_objects([]). % The empty list is a list of astral objects.
astral_objects([X|Xs]) :- % The list [X | Xs] is a list of astral objects if...
moon(X), % ... its first element X is a moon
astral_objects(Xs). % ... and the remaining list Xs is a list of astral objects
astral_object([X|Xs]) :- % Likewise for planets
planet(X),
astral_objects(Xs).
When we formulate query for a two-element list, we get all combinations of objects:
?- astral_object([A,B]).
A = B, B = europa ;
A = europa,
B = ganymede ;
A = europa,
B = jupiter ;
A = europa,
B = saturn ;
A = ganymede,
B = europa ;
A = B, B = ganymede ;
A = ganymede,
B = jupiter
%...
By unification, only rules 2 and 3 apply. In both cases we have astral_objects([X|Xs]) = astral_objects([A,B]). Remember that [A,B] is shorthand for [A|[B]] and there for X=A and Xs=[B]. The first rule of the body will unify X with the corresponding moon/planet and the recursion step describes the tail. Again, we unify astral_objects([X|Xs]) = astral_objects([B]), leading to X=B and Xs = []. Now the recursion step will only match the terminal case of the empty list and we have fully explored this path.
Now what happens if we look for an arbitrary list of astral objects?
?- astral_object(Xs).
Xs = [] ;
Xs = [europa] ;
Xs = [europa, europa] ;
Xs = [europa, europa, europa] ;
Xs = [europa, europa, europa, europa] ;
Xs = [europa, europa, europa, europa, europa]
%... does not terminate
The head astral_objects(Xs) matches all three bodies. After returning the substitution for the terminal case, it descends into the first rule over and over again. Since the length of the list is unrestricted, there are an infinite number of solutions to find before the third rule is ever tried. To avoid this, you can fairly enumerate the lists before you try to make them satisfy the predicate:
?- length(Xs,_), astral_object(Xs).
Xs = [] ;
Xs = [europa] ;
Xs = [ganymede] ;
Xs = [jupiter] ;
Xs = [saturn] ;
Xs = [europa, europa] ;
Xs = [europa, ganymede] ;
Xs = [europa, jupiter] ;
Xs = [europa, saturn] ;
Xs = [ganymede, europa]
%...
It still does not terminate, but you see the lists in ascending length and therefore the variety.
the question asked was "the getConspirators([H|T], CConspirators, Res) :- _body_ and the getConspirators([_|T], CConspirators, Res) :- _body_ parts ... My theory is that Prolog runs the getConspirators([_|T], CConspirators, Res) :- case if and only if the getConspirators([H|T], CConspirators, Res) :- case fails (returns false)"
Your theory is incorrect . Both of them will match . The only difference is that for the case of getConspirators([H|T], CConspirators, Res) :- _body_ the first element of the list will be available in the body as variable named H . But for getConspirators([_|T], CConspirators, Res) :- _body_ the first element of the list will not be available in the body as a named variable .
A good way to interpret the meaning of _ as demonstrated in this code is "a variable that I do not care to refer to later" .
I'm trying to rewrite code from Haskell to Prolog.
count :: Eq a => a -> [a] -> Int
count x = length . filter (x==)
f :: [Integer] -> [Integer]
f [] = []
f list = filter (\x -> count x list == 1) list
This code return list that contains elements that appears only once in the list.
So if I have list [1,1,2,2,3,4,4,5] this function returns [3,5]
I tried to find filter construction in Prolog but seems there no such thing. How can I make similar function in Prolog ?
To the existing answers, I would like to add an answer that is quite general in the sense that you can use it in multiple directions.
Building block: list_element_number/3
I start with the following predicate, defining a relation between:
a list Ls0
an element E
the number N of occurrences of E in Ls0
Here it is:
list_element_number(Ls0, E, N) :-
tfilter(=(E), Ls0, Ls),
length(Ls, N).
This solution uses tfilter/3 from library(reif). The predicate subsumes the function count you have posted. The main benefit of this predicate over the function is that the predicate can be used not only in those cases that even Haskell can do easily, such as:
?- list_element_number([a,b,c], a, N).
N = 1.
No, we can use it also in other directions, such as:
?- list_element_number([a,b,c], X, 1).
X = a ;
X = b ;
X = c ;
false.
Or even:
?- list_element_number([a,b,E], X, 2).
E = X, X = a ;
E = X, X = b ;
false.
Or even:
?- list_element_number([A,B,C], X, 3).
A = B, B = C, C = X ;
false.
And even in the most general case, in which all arguments are fresh variables:
?- list_element_number(Ls, E, N).
Ls = [],
N = 0 ;
Ls = [E],
N = 1 ;
Ls = [E, E],
N = 2 ;
Ls = [E, E, E],
N = 3 .
We can fairly enumerate all answers like this:
?- length(Ls, _), list_element_number(Ls, E, N).
Ls = [],
N = 0 ;
Ls = [E],
N = 1 ;
Ls = [_160],
N = 0,
dif(E, _160) ;
Ls = [E, E],
N = 2 .
Main predicate: list_singletons/2
Using this building block, we can define list_singletons/2 as follows:
list_singletons(Ls, Singles) :-
tfilter(count_one(Ls), Ls, Singles).
count_one(Ls, E, T) :-
list_element_number(Ls, E, Num),
cond_t(Num=1, true, T).
This uses cond_t/3 and (again) tfilter/3 from library(reif).
Sample queries
Here are a few sample queries. First, the test case you have posted:
?- list_singletons([1,1,2,2,3,4,4,5], Singles).
Singles = [3, 5].
It works as desired.
Now a case involving variables:
?- list_singletons([A,B], Singles).
A = B,
Singles = [] ;
Singles = [A, B],
dif(A, B).
On backtracking, all possibilities are generated: Either A = B holds, and in that case, there is no element that occurs only once. Or A is different from B, and in that case both A and B occur exactly once.
As a special case of the above query, we can post:
?- list_singletons([A,A], Singles).
Singles = [].
And as a generalization, we can post:
?- length(Ls, _), list_singletons(Ls, Singles).
Ls = Singles, Singles = [] ;
Ls = Singles, Singles = [_7216] ;
Ls = [_7216, _7216],
Singles = [] ;
Ls = Singles, Singles = [_7828, _7834],
dif(_7828, _7834) ;
Ls = [_7216, _7216, _7216],
Singles = [] ;
Ls = [_7910, _7910, _7922],
Singles = [_7922],
dif(_7910, _7922) .
Enjoy the generality of this relation, obtained via logical-purity.
A more simple version :
filter_list(L,OutList):-findall(X, (select(X,L, L1),\+member(X, L1)) , OutList).
?- filter_list([1,1,2,2,3,4,4,5],L).
L = [3, 5].
Without findall, you can try
filter_list(In, Out) :- filter_list(In, _, Out).
filter_list([], [], []).
filter_list([H|T], L1, L2) :-
filter_list(T, LL1, LL2),
( member(H, LL1)
-> L1 = LL1, L2 = LL2
; (select(H, LL2, L2)
-> L1 = [H|LL1]
; L1 = LL1, L2 = [H|LL2])).
without counting...
filter_uniques([],[]).
filter_uniques([H|T],F) :-
delete(T,H,D),
( D=T -> F=[H|R],S=T ; F=R,S=D ),
filter_uniques(S,R).
a more direct rewrite of your code, with library(yall) support for inlining of the filter predicate (the first argument to include/3)
filt_uniq(L,F) :-
include({L}/[E]>>aggregate(count,member(E,L),1),L,F).
A simple version:
(see the comment by #false below, the version with findall/3 has some inconsistency problems in more complex queries but second version looks ok however it is definitely not so efficient ).
filter_list(L,OutList):-findall(X, (member(X,L),count(X,L,N),N=:=1) , OutList).
count(_,[],0).
count(X,[X|T],N):-count(X,T,N1),N is N1+1.
count(X,[X1|T],N):-dif(X,X1),count(X,T,N).
The predicate filter_list/2 uses findall/3 and simply states find all X that belong to the list L and count returns 1 and store them in OutList.
Example:
?- filter_list([1,1,2,2,3,4,4,5],L).
L = [3, 5].
You could write filter_list/2 without using findall/3 like:
filter_list(L,OutList):- filter_list(L,OutList,L).
filter_list([],[],_).
filter_list([H|T],[H|T1],L):-count(H,L,N), N=:=1, filter_list(T,T1,L).
filter_list([H|T],T1,L):-count(H,L,N), N > 1, filter_list(T,T1,L).
I found a similar post but it didn't work for me. So please don't try to redirect me to other links.
This is the result that I want:
removeadj([a,a,a,b,c,c,a,a],[a,b,c,a]).
>True.
I tried this code:
concatener([],R,R).
concatener([X|Y],L,R):-concatener(Y,L,R1),R=[X|R1].
removeadj([],[]).
removeadj([X],[X]).
removeadj([X|Y],R):- Y=[X|L],removeadj(Y,R1),concatener([],R1,R).
removeadj([X|Y],R):- removeadj(Y,R1),concatener(X,R1,R).
When I try a list with one element duplicated many times, it works:
removeadj([a,a,a,a,a],[a]).
> True
But when I use different elements, it doesn't work:
removeadj([a,a,a,b],[a,b]).
> False.
I do not see where the problem is, so I can't fix it. Please I need your help.
Relational names
The first is to reconsider the name of your relation. Currently, it suggests that someone has to do something. removeadj that's a command. Quite an adequate name in a programming language where commands are the ruling metaphor. But not in Prolog.
In Prolog, we have relations. A name that reflects this relationness is often very helpful. Why not list_list/2? After all, your relation is about two lists! OK, maybe that name was a bit too general. What about list__list_without_adjacent_elements/2? Lengthy, but relational. Maybe we shorten that to: list_noadjs/2. Note the s at the end: That means: it's a plural which means it's a list.
Observe properties
Before thinking about "doing" this or that. Rather muse about concrete examples - preferably ground examples, as you have given them. And about other properties. One observation is that all elements of the second list will be there in the first. In fact not only that. But they will also occur in the same order. Let me try to formulate that. Of course, that observation is not sufficient to write an entire predicate. But here comes the cool thing in Prolog: We do not need to implement everything. We can start with gross generalizations that contain all what we want plus some more.
Start with a too general definition.
To show you the most extreme, let's try:
list_noadjs(_Xs, _Ys).
This is the mother of all binary relations! That definition always succeeds, no matter what. Evidently, we will have to specialize it. Say, by looking at the second argument which is a list:
list_noadjs(_Xs, []).
list_noadjs(_Xs, [Y|Ys]) :-
list_noadjs(_, Ys).
If the list is [] so will be the original one. And both start with the same element!
list_noadjs(Xs, []) :-
Xs = [].
list_noadjs(Xs, [Y|Ys]) :-
Xs = [Y|_],
list_noadjs(_, Ys).
or more compactly:
list_noadjs([], []).
list_noadjs([Y|_Xs], [Y|Ys]) :-
list_noadjs(_, Ys).
Now, the first list contains elements of the second list. And in between something else:
list_noadjs([], []).
list_noadjs([Y|Xs0], [Y|Ys]) :-
list_(Xs0,Xs1),
list_noadjs(Xs1, Ys).
list_(Xs,Xs).
list_([_|Xs0],Xs) :-
list_(Xs0,Xs).
Is this already our relation? Let's give it a try:
?- list_noadjs("aaab",Ys).
Ys = "aaab"
; Ys = "aaa"
; Ys = "aab"
; Ys = "aa"
; Ys = "aab"
; Ys = "aa"
; Ys = "ab" % <===== * RRRIGHT !!!!***
; Ys = "a"
; false.
(Btw. I am using library(double_quotes) to make answers more readable.)
So we do have the expected solution. Alas, there are many incorrect solutions, too! We will have to continue to specialize this program:
list_noadjs([], []).
list_noadjs([Y|Xs0], [Y|Ys]) :-
eq_list_(Y, Xs0,Xs1),
list_noadjs(Xs1, Ys).
eq_list_(_, Xs,Xs).
eq_list_(Y, [Y|Xs0],Xs) :-
eq_list_(Y, Xs0,Xs).
Now this is much better, but still not perfect:
?- list_noadjs("aaab",Ys).
Ys = "aaab"
; Ys = "aab"
; Ys = "aab"
; Ys = "ab" % !!! Right
; false.
We have to further specialize the program: After a sequence of identical elements, there must be something else:
list_noadjs([], []).
list_noadjs([Y|Xs0], [Y|Ys]) :-
eq_list_(Y, Xs0,Xs1),
nohead(Xs1, Y),
list_noadjs(Xs1, Ys).
eq_list_(_, Xs,Xs).
eq_list_(Y, [Y|Xs0],Xs) :-
eq_list_(Y, Xs0,Xs).
nohead([], _X).
nohead([X|_], Y) :-
dif(X, Y).
So that's our relation.
Enjoy the relation!
Seriously. Don't just use the test cases you had. You have now a relation! That's not a function in disguise, it is truly more than that. Try it out! Ask completely unusual things, like:
?- list_noadjs(Xs,"abc").
Xs = "abc"
; Xs = "abcc"
; Xs = "abccc"
; Xs = "abcccc"
; ... .
So here we ask: Which lists correspond to "abc"? Note that only c is repeated! All the other solutions are hidden behind this wall of infinity. But we can play a little trick to get them:
?- length(Xs,N), list_noadjs(Xs,"abc").
Xs = "abc", N = 3
; Xs = "abcc", N = 4
; Xs = "abbc", N = 4
; Xs = "aabc", N = 4
; Xs = "abccc", N = 5
; Xs = "abbcc", N = 5
; Xs = "abbbc", N = 5
; Xs = "aabcc", N = 5
; Xs = "aabbc", N = 5
; Xs = "aaabc", N = 5
; Xs = "abcccc", N = 6
; ... .
Don't shy away from non-termation.
We have already seen it: Very often, we get infinitely many solutions. And (I must admit) it's even worse: Sometimes, our relations do not even terminate.
Here is one such example. Say, is there a way that the list in the second argument contains duplicates? Or that the following holds:
?- list_noadjs(Xs,[X,X]).
loops.
Prolog answers: mumble, mumble, lemme see...
To master Prolog, you will have to understand this in detail. But for the moment, there is often a good way out:
Specialize queries to get termination
So instead of asking: Is there any term that may correspond to [X,X] we may ask: Is there a list of size 5 (or any other finite size). Now Prolog denies this:
?- Xs = [_,_,_,_,_], list_noadjs(Xs,[X,X]).
false.
That's not the universal answer you wanted. But it is better than nothing.
Sometimes all these queries are too much for you. Let Prolog do the thinking for you by:
Enumerating all solutions
Often, this is very simple. Start with the most general query. The big advantage here is that no thinking is required on your side at all. And still you look like a pro:
?- list_noadjs(Xs,Ys).
Xs = [], Ys = []
; Xs = [_A], Ys = [_A]
; Xs = [_A,_B], Ys = [_A,_B], dif(_B,_A)
; Xs = [_A,_B,_C], Ys = [_A,_B,_C], dif(_B,_A), dif(_C,_B) ?
; Xs = [_A,_B,_C,_D], Ys = [_A,_B,_C,_D], dif(_B,_A), dif(_C,_B), dif(_D,_C)
; Xs = [_A,_B,_C,_D,_E], Ys = [_A,_B,_C,_D,_E], dif(_B,_A), dif(_C,_B), dif(_D,_C)
; ... .
What we got here are so called answers. A single answer may contain infinitely many solutions. Think of this: You are looking at infinity! Some conditions (called constraints) must hold, like dif/2. But that's it.
The third answer was:
Xs = [_A,_B], Ys = [_A,_B], dif(_B,_A)
So Xs and Ys are the same list with two distinct elements. So this answer implies Xs = "ab", Ys = "ab" but also Xs = [1,2], Ys = [1,2] and many, many more.
Even better, enumerate all answers in a systematic ("fair") manner:
?- length(Xs, N), list_noadjs(Xs,Ys).
Xs = [], N = 0, Ys = []
; Xs = [_A], N = 1, Ys = [_A]
; Xs = [_A,_B], N = 2, Ys = [_A,_B], dif(_B,_A)
; Xs = [_A,_A], N = 2, Ys = [_A]
; Xs = [_A,_B,_C], N = 3, Ys = [_A,_B,_C], dif(_B,_A), dif(_C,_B)
; Xs = [_A,_B,_B], N = 3, Ys = [_A,_B], dif(_B,_A)
; Xs = [_A,_A,_B], N = 3, Ys = [_A,_B], dif(_B,_A)
; Xs = [_A,_A,_A], N = 3, Ys = [_A]
; Xs = [_A,_B,_C,_D], N = 4, Ys = [_A,_B,_C,_D], dif(_B,_A), dif(_C,_B), dif(_D,_C)
; ... .
These are all solutions up to length 3. There are no other! We know this for sure because the last answer is already of size 4. So all solutions below are here already!
Often looking at such answers is very helpful. For example, it permits you to rapidly detect errors (like in the other answer that was given previously). So, don't tell nobody about that trick.
The last clause in the predicate still has an issue:
removeadj([X|Y], [X|R1]):- removeadj(Y, R1).
In the event that the element following X is also X, X is still carried in the head of the second argument. This clause must check if the following element is different before allowing it in the second argument:
removeadj([X,Y|L], [X|R]) :-
dif(X,Y),
removeadj([Y|L], R).
Here, Y is at the head of the second list only if it's different from X.
So the whole solution looks like:
removeadj([], []).
removeadj([X], [X]).
removeadj([X,X|T], R) :- % drop an X if next element is X
removeadj([X|T], R).
removeadj([X,Y|T], [X|R]) :- % carry X along if next element different
dif(X,Y),
removeadj([Y|T], R).
removeadj([],[]).
removeadj([X],[X]).
removeadj([X|Y],R):- Y=[X|L],removeadj(Y,R1),R=R1.
removeadj([X|Y],[X|R1]):- removeadj(Y,R1).
I have written a small Prolog script which, taken a list, removes all values below a threshold N:
rem_under([], []).
rem_under([X|Xs], [X|Ys]) :-
X >= 10,
rem_under(Xs, Ys).
rem_under([X|Xs], Ys) :-
X < 10,
rem_under(Xs, Ys).
So, for example:
2 ?- rem_under([2,15,16,3,5,19],L).
L = [15, 16, 19]
I then wanted to make a similar function which removed all elements ABOVE a threshold N:
rem_over([], []).
rem_over([X|Xs], [Ys]) :-
X > 10,
rem_over(Xs, Ys).
rem_over([X|Xs], [X|Ys]) :-
X <= 10,
rem_over(Xs, Ys).
Which however returns:
1 ?- rem_over([2,15,17,6],L).
false.
Any idea why this is? Other than a few cosmetic changes, I have only swapped the < and > signs.
Your second clause is incorrect, because its second argument is [Ys] — a list of length 1:
rem_over( [X|Xs] , [Ys] ) :-
X > 10,
rem_over(Xs, Ys).
Once you've decided the head of the source list is greater than 10, you recurse down on the tail of the source list and the the contents of the result list.
Try this:
rem_over( [] , [] ) . % source list exhausted? success!
rem_over( [X|Xs] , Ys ) :- % source list non-empty?
X > 10, % - head greater than the threshold?
rem_over(Xs, Ys) % - chuck it and recurse down on the remainder of the source list
. %
rem_over( [X|Xs] , [X|Ys] ) :- % source list non-empty? add the head to the result
X =< 10, % - IF it's less than or equal to the threshold
rem_over(Xs, Ys). % - then recurse down on the remainder
Another way to get there:
rem_over( [] , [] ) .
rem_over( [X|Xs] , Ys ) :-
( X > 10 -> Y1 = Ys ; Y1 = [X|Ys] ) ,
rem_over(Xs,Y1)
.
HINT: because you have a singleton variable (that is considered to be a list) inside [].
ANSWER: in the head of the 2nd clause should be
rem_over([X|Xs], Ys) :-
Having trouble understanding how Prolog works. I'm tryig to write a rule that takes three lists of integers as input (representing sets) and puts the integers that belong to both the first and second list in the third list.
Example:
?-inter([10,20,30,40],[10,50,40,60], List3 )
List3 = [10, 40]
So far I have this, that can recognize if a list contains a certain letter:
mymember(X,[X|T]).
mymember(X,[H|T]) :- mymember(X,T).
There's actually an inbuilt library to sort that all out for you, known as ordsets.
inter(X, Y, Z) :-
list_to_ord_set(X, L1),
list_to_ord_set(Y, L2),
ord_intersection(L1, L2, Z).
Using your example input you get the following
| ?- inter([10,20,30,40],[10,50,40,60],X).
X = [10,40] ? ;
no
inter(Xs, Ys, Zs) will be true when each element in Zs also is in Xs and in Ys.
But Zs are unknown, then a more constructive approach is required.
Here it is: iterate on Xs and store in Zs each element that is in Ys.
An example of iteration is mymember/2, you can see that it requires a recursive predicate.
The other idiomatic part of the above statement is store in Zs, Prolog has a peculiar way to do such things, using pattern matching.
inter([X|Xs], Ys, [X|Zs]) :-
mymember(X, Ys), inter(Xs, Ys, Zs).
You will need to complete inter/3 with other 2 clauses: base recursion, i.e. when all Xs elements have been processed, and the case where X is not a member of Ys.
Try something like this, using the builtins member/2 and setof\3:
set_intersection( As , Bs , Xs ) :-
set_of( X , ( member(X,As) , member(X,Bs) ) , Xs )
.
One should note that this will fail if the lists As and Bs have no elements in common. An alternative would be use findall/3 rather than set_of/3. findall/3 will hand back and empty list rather than failure if the goal is not satisfied:
set_intersection( As , Bs , Xs ) :-
findall( X , ( member(X,As) , member(X,Bs) ) , Xs )
.
However findall/3 returns a bag (duplicates are allowed) rather than a set (no duplicates allowed), so if your two source lists aren't sets, you won't get a set out.
member/2 is a builtin predicate that unifies its first argument with an element of the list — the equivalent of
member(X,[X|_).
member(X,[_|Xs) :- member(X,Xs) .
And, finally, as #chac noted in his answer, you can recursively traverse the list.
set_intersection( [] , _ , [] ) . % the intersection of the empty set with anything is the empty set.
set_intersection( [A|As] , Bs , [A|Xs] ) :- % if the list is non-empty,
member(A,Bs) , % - and A is a member of the 2nd set
! , % - we cut off alternatives at this point (deterministic)
set_intersection( As , Bs , Xs ) % - and recurse down on the tail of the list.
.
set_intersection( [_|As] , Bs , Xs ) :- % if the list is non-empty, and A is NOT a embmer of the 2nd set
set_intersection( As , Bs , Xs ) % we just recurse down on the tail of the list.
.
#chac's technique builds the result list as he goes, something like:
[a|X]
[a,b|X]
[a,b,c|X]
The final unification, the special case of the empty list unifies the unbound tail of the list with [] making the list complete, so the final [a,b,c|X] becomes
[a,b,c]
A little prolog magic. An alternative that might be easier to understand is to use a worker predicate with an accumulator:
%
% set_intersection/3: the public interface predicate
%
set_intersection( As , Bs , Xs ) :-
set_intersection( As , Bc , [] , T ) % we seed our accumulator with the empty list here
.
%
% set_intersection/4: the private worker bee predicate
%
set_intersection( [] , _ , T , Xs ) :- % since our accumulator is essentially a stack
reverse(T,Xs) % we need to reverse the accumulator to
. % put things in the expected sequence
set_intersection( [A|As] , Bs , T , Xs ) :-
member( A, Bs ) ,
! ,
T1 = [A|T] ,
set_intersection( As , Bs , T1 , Xs )
.
set_intersection( [_|As] , Bs , T , Xs ) :-
set_intersection( As , Bs , T , Xs )
.