Prolog predicates involving lists - prolog

I want to write a predicate that finds a particular element in a list, by comparing the lists. For example the data I could have for instance could be like:
likes(phil, [apple, banana, orange]).
likes(hetti, [apple, cherry, grapes]).
etc.
I just want someone to explain how something like this would work, because I've been trying to use member or select; but it seems to be more difficult to find information on this. Could I use pattern matching?

It seems likely that you want to know what the common likes are between phil and hetti. If so, then this is the code:
?- bothlike(phil, hetti, Ls), write(Ls), nl.
bothlike(X, Y, Ls) :-
likes(X, Xs),
likes(Y, Ys),
intersection(Xs, Ys, Ls).
likes(phil, [apple, banana, orange]).
likes(hetti, [apple, cherry, grapes]).
intersection([], _, []).
intersection([H1|T1], L2, L3) :-
member(H1, L2),
!,
L3 = [H1|T3],
intersection(T1, L2, T3).
intersection([_|T1], L2, L3) :-
intersection(T1, L2, L3).
It gives the answer [apple].

Related

Create a list in prolog from facts

I want to create a list from facts like:
table(mickel).
table(harris).
table(wolfgang).
table(yanis).
table(antti).
table(peter).
table(jeroen).
table(johan).
table(luis).
table(eric).
But i don't want to use built-in rules or predicates,
unless i define them by myself.
The result almost is like that:
?- seats(Seats).
Seats = [yanis,antti,peter,jeroen,johan,luis,eric,michel,
harris,wolfgang]
I don't know what to do,please help.
You must create your own findall predicate, this post may help:
seats(L) :- find([], L), !.
find(Acc, Loa) :- table(Y), uList(Y, Acc, AccNew), find(AccNew, Loa).
find(Acc, Acc).
uList(X, [], [X]) :- !.
uList(H, [H|_], _) :- !, fail.
uList(X, [H|T], [H|Rtn]) :- uList(X, T, Rtn).
Consult:
?- seats(L).
L = [mickel, harris, wolfgang, yanis, antti, peter, jeroen, johan, luis|...].

Remove duplicate elements from list

This is my code
removevowels(L1, L2) :-
removevowels(L1, L2, []).
removevowels([], [], _).
removevowels([X|L1], [X|L2], Aux) :-
consonant(X),
not(member(X, Aux)),
removevowels(L1, L2, [X|Aux]).
removevowels([X|L1], L2, Aux) :-
not(consonant(X)),
removevowels(L1, L2, Aux).
If i run this:
?- removevowels([a,m,m,n], X).
It should print
X = [m, n]
but it's giving false and if i run this
?- removevowels([a,m,n], X).
X = [m,n]
It's alright when it doesn't have repeated elements.
Auxiliar predicates used:
member(X, [X|_]).
member(X, [_|Tail]) :-
member(X, Tail).
consonant(b)
consonant(c), etcetc ....
What's wrong in my code?
The best is to replace not/1 by the ISO (\+)/1 first.
For debugging, the first thing you would do is to minimize the problem. E.g., the query
?- removevowels([m,m],X).
is just as bad. But much smaller. So what are your rules for consonants? There is a single rule:
removevowels([X|L1], [X|L2], Aux) :-
consonant(X),
\+member(X, Aux),
removevowels(L1, L2, [X|Aux]).
So consonants have to occur only once, the next occurrence makes this fail already.
Should you still not be sure why the query fails, you might also want to generalize the query. In stead of seeing that removevowels([m,m],X) fails, you might ask
?- removevowels([m,Y],X).
which means: Is there any Y such that there is a solution. However, this method only works, if your program is "relational". In your case the last rule, however prevents this:
removevowels([X|L1], L2, Aux) :-
\+consonant(X),
removevowels(L1, L2, Aux).
It will never succeed with X being an uninstantiated variable. I'd rather use instead:
removevowels([X|L1], L2, Aux) :-
vowel(X),
removevowels(L1, L2, Aux).
Back to consonants:
What you are missing is either a separate rule for consonants that are already present, or some "defaulty" if-then-else.
Further, this extra checking might not be the most effective way to handle this. Maybe just extract the vowels first, and then sort/2 them.
in second clause, there are two 2 conditions in join, while the last clause has only one. I would commit the good case with a cut, and let the last clause only act as a trusted skip clause:
removevowels([], [], _).
removevowels([X|L1], [X|L2], Aux) :-
consonant(X),
not(member(X, Aux)),
!, removevowels(L1, L2, [X|Aux]).
removevowels([_X|L1], L2, Aux) :-
removevowels(L1, L2, Aux).
using if/then/else construct for the last 2 clauses, we avoid the problem noted by false:
removevowels([], [], _).
removevowels([X|L1], R, Aux) :-
( consonant(X),
not(member(X, Aux))
-> R=[X|L2],
removevowels(L1, L2, [X|Aux])
; removevowels(L1, R, Aux)
).

Prolog variable gets no value

I've written the following code in prolog:
contains(L1, []).
contains(L1, [X | T2]) :- member(X, L1), contains(L1, T2).
minus(L, [], L).
minus(L1, L2, L3) :- contains(L1, L3), nomembers(L3, L2).
nomembers(L1, []).
nomembers(L1, [X | T2]) :- not(member(X, L1)), nomembers(L1, T2).
contains(L1, L2) returns true if all of the members in L2 appear in L1. (contains([1,2],[1,1,1]) is true).
minus(L1, L2, L3) returns true if L3=L1\L2, meaning L3 consists of members of L1 but not of L2.
When I ask minus([1,2,3,4],[2,1],L), I get the answer that L=[], although logically it should be L=[3,4]. Does someone know why?
Above comment of mbratch is very helpful.
Notice, that your current minus(L1, L2, L3) definition is: All members of L3 are in L1 and no member from L3 is in L2.
Prolog is giving you good answer with L3 = [], it fits for definition I wrote above.
EDIT: Below code should do what you want, but currently I don't have prolog on my computer, so I can't test it.
remove(X, [X|T], T) :- !.
remove(X, [H|T], [H|T2]) :- remove(X, T, T2).
minus(L1,[],L1).
minus(L1,[H|T2],T3) :- member(H, L1), !, remove(H,L1,L4), minus(L4, T2, T3).
minus(L1,[H|T2],[H|T3]) :- minus(L1, T2, T3).
remove(X,LA,LB) which says: LB is LA without it first occurrence of X, so it's just removing element from the list.

Getting list of solutions in Prolog

I am learning prolog and I am reading a book called Programming Prolog for Artificial Intelligence. As practice I want to learn how to extend one of the examples in this book. Can someone please help?
Say you have these facts:
parent(pam, bob). %pam is a parent of bob
parent(george, bob). %george is a parent of bob
How would I write a prolog predicate that would give me a list of bobs parents? For example:
list_parents(bob, L).
L = [pam, george] ;
L = [george, pam] ;
true.
An all-solutions predicate like findall/3 might do the trick:
list_parents(P, L) :-
findall(Parent, parent(Parent, P), L).
Simply put, findall/3 finds all bindings for Parent in the 'backtrack-able' goal parent(Parent, P), and puts all bindings of Parent into the list L. Note that this won't remove duplicates, but you can do a sort/2 to L before returning it to create a set. Executing this:
?- list_parents(bob, L).
L = [pam, george].
If you don't have findall/3 in your PROLOG implementation, you could do it manually like this:
list_parents(P, L) :-
list_parents(P, [], L).
list_parents(P, Acc, L) :-
parent(Parent, P),
\+ member(Parent, Acc), !,
list_parents(P, [Parent|Acc], L).
list_parents(_, L, L).
This version sends calls to list_parents/2 off to an accumulator-version, list_parents/3. The latter tries to collect Parent bindings also, as long as we haven't seen them before (hence the \+ member check), and returns the list where no new Parent bindings accumulated into the Acc list can be found. Executing this gives us the same result as the first option:
?- list_parents(bob, L).
L = [pam, george].
Try this:
parent(pam, bob). %pam is a parent of bob
parent(george, bob). %george is a parent of bob
list_parents(A, Es, [X|Xs]) :- parent(X, A), \+ member(X, Es), list_parents(A, [X|Es], Xs).
list_parents(A, Es, []).
That was an inefficient method, a better method will need a "solutions" higher-order predicate.
list_parents(X, Ys) :- solutions(parent, [X, W], 1, Ys)

Searching Prolog structures

I'm interested in formulae made up from lots of conjunctions (part of a larger problem). I want to write a program that takes something like this:
:- get_params(conj(conj(a,b),c),X)
and returns a list of all the parameters of the conjunctions i.e. X=[a,b,c]. At the moment I can do
:- get_params(conj(a,b),X) to get X=[a,b]
using simple Prolog pattern matching but how would you go about doing things such as
:- get_params(conj(conj(a,b),c),X) to get X=[a,b,c]
It seems really simple but I've been struggling all day!
Since you are describing a list, consider using DCG notation:
params(conj(A,B)) --> !, params(A), params(B).
params(X) --> [X].
Example:
?- phrase(params(conj(conj(a,b),c)), Ps).
Ps = [a, b, c].
Assuming that all conj functors are binary:
get_params(X, Y, L) :-
get_params(X, L1),
get_params(Y, L2),
append(L1, L2, L).
get_params(conj(X, Y), L) :-
get_params(X, Y, L), !.
get_params(A, [A]).

Resources