Prolog predicate doesn't resolve - list

This may be a rookie mistake, but I'm trying to solve this question:
Find the query to obtain the following answer using the findall predicate: Obtain a list of persons who work in a city other than the one where they live:
L = [suzy, paul].
This is the database:
city(ottawa,ontario).
city(toronto,ontario).
city(kingston,ontario).
city(gatineau,quebec).
city(montreal,quebec).
company(shopify,ottawa).
company(rossvideo,ottawa).
company(dium,gatineau).
company(uber,toronto).
company(deepmind,montreal).
company(google,toronto).
person(annie,gatineau).
person(paul,gatineau).
person(suzy,gatineau).
person(robert,gatineau).
person(tom,ottawa).
person(tim,kingston).
person(joe,montreal).
person(jane,ottawa).
person(marie,ottawa).
person(jack,toronto).
person(simon,toronto).
employee(annie,dium).
employee(tom,shopify).
employee(jane,shopify).
employee(marie,shopify).
employee(joe,deepmind).
employee(jack,google).
employee(simon,google).
employee(suzy,shopify).
employee(paul,rossvideo).
employee(marie,rossvideo).
employee(simon,uber).
Here is the predicate I tried to use to solve it:
worksIn(n, Y) :-
employee(n, Comp),
company(Comp, Y).
But it only returns false. Does anyone know how to fix it?

I did:
worksIn(P):- person(P,CL), employee(P, CO), company(CO, CW), CL/=CW.
so the final answer is:
findall(P, worksIn(P), L).
I'm not sure if we can add the "worksIn" thing in or not

when use variables, first letter must be uppercase.

Related

Converting list of clauses to a query?

let say i have the following facts :
book(65).
own(named('Peter'), 65).
now got the query as a list of clauses :
[what(A), own(named('Peter'), A)]
or
[who(X), book(A), own(X, A)] .
how do I make a rule that accept this list and return the result. Keep in mind that the question could be Why,When,Who...
I went the usual way :
query_lst([]).
%% query_lst([what(Q)|T], Q) :- query_lst(T).
query_lst([H|T]) :- write('?- '),writeln(H),
call(H), query_lst(T).
but this does not allow binding of Q in wh(Q) to the answer which could be in any of the facts that are called by call()
Additional complication I did not forsee is that the query :
(what(A), own(named('Peter'), A).
would fail, because there is no what(X), fact in the DB.
I have to just bind somehow the variable A /that is in what()/ to query_lst(Goals,A) and of course remove what(X) from the list /which i can do with select/3 /
any idea how to bind list-Wh-var to query_lst result ?
my current solution (assumes Q is first element):
query_lst([G|Gs],Res) :- G =.. [Q,Res], member(Q,[what,why,who,when]), lst2conj(Gs,Conj), call(Conj).
Simply convert the list of goals into a conjunction and call it:
list_to_conjunction([], true).
list_to_conjunction([Goal| Goals], Conjunction) :-
list_to_conjunction(Goals, Goal, Conjunction).
list_to_conjunction([], Conjunction, Conjunction).
list_to_conjunction([Next| Goals], Goal, (Goal,Conjunction)) :-
list_to_conjunction(Goals, Next, Conjunction).
Then:
query_list(Goals) :-
list_to_conjunction(Goals, Conjunction),
call(Conjunction).
You got an answer, but it was an answer to your question, not to what you really wanted. Also, you edited your question after you accepted that answer, which isn't very helpful. Typically it's better to open a new question when you have... a new question.
Here is an answer to what you seem to want, which is not exactly what you asked. You have lists of the form [WhPart | Rest] where the WhPart is a wh-word with a variable, and the Rest is a list of goals. You want to execute these goals and get the variable in the wh-term bound.
The good news is that, since the variable in the wh-word also occurs in the goals, it will be bound if you execute them. No extra work is needed. Executing the goals is enough. If the wh-part is really at the start of the list, you can do the whole thing like this:
query([_WhPart | Body]) :-
call_body(Body).
call_body([]).
call_body([Goal | Goals]) :-
call(Goal),
call_body(Goals).
For example:
?- query([who(X), book(A), own(X, A)]).
X = named('Peter'),
A = 65.
?- query([what(A), own(named('Peter'), A)]).
A = 65.
As you can see, there is no need to convert the query to a conjunctive goal: Executing the queries in sequence is exactly the same as executing their conjunction.
Also, it doesn't actually matter which wh-word is used; the only thing that really matters is the variable contained within the term. For this reason the above version does no checking at all, and the _WhPart could be anything. If you want to check that it is a valid term, you can do the following:
query([WhPart | Body]) :-
wh(WhPart),
call_body(Body).
wh(who(_X)).
wh(what(_X)).
wh(when(_X)).
This buys you some "type checking":
?- query([foo(A), own(named('Peter'), A)]).
false.
But not a lot, since you don't know if the wh-word actually fits what is being asked:
?- query([when(A), own(named('Peter'), A)]).
A = 65.

prolog predicate returns facts(?)

First of all, if the answer to my question is here or here
I couldn't find it so please don't kill me.
I want to write a Prolog predicate which returns a list of this form:
(list[elem, elem2], list[elem3, elem4], list[elem5, elem6]).
now I can think of several ways to return a list of this form:
([elem, elem2], [elem3, elem4],[elem5, elem6]).
but how do I make the word "list" appear there as well? what is it even? a fact? another predicate?
Thanks in advance!
You can create a compound term using the standard =../3 built-in predicate. For example:
| ?- Term =.. [list, [1,2,3]].
Term = list([1,2,3])
yes
But note that the syntax that you're trying to use, list[elem5, elem6], is not valid. Are you trying to mimic an array representation? If so, maybe use instead list(elem5, elem6)? For example:
| ?- Term =.. [list, elem5, elem6].
Term = list(elem5, elem6)
yes

Unifying list of lists prolog

I googled this but cant find the answer, so here you go:
I have this function in prolog:
ing(Lis) :- findall(I,( recipe2(_,ingredients(I,_)) ),Lis).
This function search and returns me a list of lists like this:
L = [['wheat flour', egg, salt], ['wheat flour', cheese, olives, tomato, salt, basil], ['wheat flour', potatoes, salt], [milk, egg, sugar]].
I want to unify that list of lists in only one list, so i can get out duplicates. I know i have to use recursion, but thats all i know.
Thanks in advance.
You may simply modify the predicate like such:
ing(Lis) :-
setof(E, X^Y^I^( recipe2(X, ingredients(I,Y)), member(E, I) ), Lis).
member/2 is a built-in predicate that unifies the first argument with an element of a list in the second argument. It is non-deterministic.
The use of X^Y^I^ are existential quantifiers to ensure that you only get your results in one solution. It essentially says,
There exists an X, Y, and I for any element E that is a part of an
ingredient list, (I).
Using setof/3 also ensures that any solution you get will be a collection of unique elements.
Documentation (SWI-Prolog) for member/2 and setof/3

How do I check if the first occurrence of a number equals to x?

I'm am trying to find a way to check if the first first a number in a nested list equals to x.
check(X,L), X= is a number and Y is a nested list.
check(2,[a,b[g,4],y,8]).
false
check(2,[a,b[g,2],y,8]).
true
It seems that recursion would do best. But I still do not understand how to approach it with recursion in Prolog.
I had this idea of flattening the nested list and then check if first element is a number and if it equals to X.
Can anyone help me?
Your idea must be refined. Some code is needed to match the first occurrence. I would 'cheat':
check(X,L) :- flatten(L,F), include(number,F,[X|_]).
It can be nicely done with simple recursion:
check(X,[X|_]) :- number(X).
check(X,[NL|_]) :- is_list(NL), check(X, NL).
check(X,[V|L]) :- not(number(V)), check(X, L).
UPDATE:
This fixes problem found by #CappelliC:
check(X,[X|_]) :- number(X).
check(X,[V|L]) :- not(number(V)), not(is_list(V)), check(X, L).
check(X,[NL|L]) :- is_list(NL), append(NL,L,BL), check(X, BL).
Results:
?- check(2,[a,b,[g,4],y,8]).
false.
?- check(2,[a,b,[g,2],y,8]).
true .

a challenging list question on prolog

I am new on prolog. Can you help me to solve this problem, please.
exam(math, paul).
exam(phys, paul).
exam(cmpe, sofia).
exam(bio, george).
I want to implement the predicate otherExam(L, N). L is a lesson, and N is the list of all lessons (except L) haved by student of L.
otherExam(math,X). returns [phys]
otherExam(cmpe,X). returns []
otherExam(chem,X). returns false (no such lesson)
otherExam(math,[phys]) returns true
otherExam(X,[phys]). returns math
I haved stucked with this problem. If you help me, I will be very happy :))
check findall/3 and select/3
findall/3 is used to get all the possible results from a query
for example, findall(X,ancestor(X,paul),L) will find all X such as X is an ancestor of paul and will put them in the list L