Prolog queries beginner - prolog

Given the predicates
hasAccount(Person,Bank,Amount) – the Person has an account at the Bank with the balance Amount
lives(Person,City) – the Person lives in the City
created(Person,Bank,Month,Year) – the Person opened an account at the Bank in Month of the Year
how would you find someone who has the oldest account at the same bank using only the following "- , < =< > >= not" operators? I'm deeply lost!

Based on your comment, \+ is used for not (not proveable):
created(Who,Somebank,Month1,Year1),
\+ ( created(_,Somebank,Month2,Year2), older(Month2,Year2,Month1,Year1) )
with older/4 defined as:
older(_Month2,Year2,_Month1,Year1) :- Year2 < Year1.
older(Month2,Year,Month1,Year) :- Month2 < Month1.

Related

Visual Prolog 5.2 The variable is not bound in this clause

I have "in" predicate that goes through "people". But the X doesnt get a "person" and returns false, as i understood. Test goal and Run throw the same error
domains
person = c(name, nationality)
people = person*
name, nationality = symbol
predicates
name(person, name)
nationality (person, nationality)
in(person, people)
solve
clauses
name(c(N,_), N).
nationality (c(_,T), T).
in(X,[X,_,_,_]). %Error here
in(X,[_,X,_,_]).
in(X,[_,_,X,_]).
in(X,[_,_,_,X]).
solve :- in(C1, People), name(C1, brown),
in(C2, People), name(C2, clemens),
in(C3, People), name(C3, grifit),
in(C4, People), name(C4, grin),
in(C5, People), nationality(C5, canadian),
in(C6, People), nationality(C6, american),
in(C7, People), nationality(C7, australian),
in(C8, People), nationality(C8, british),
not(nationality(C1, british)),
not(nationality(C2, british)),
not(nationality(C3, american)),
not(nationality(C3, australian)),
not(nationality(C1, australian)),
not(nationality(C4, australian)),
write(People), nl.
goal
solve.
I expect X to be bound to the person (people item). What am I doing wrong?

Is there a way to reach the same result in a clause using less variables?

I am trying to find/understand another way to reach a result by calling more predicates in a clause when using less free variables.
Coming from this problematic How to correctly filter a clause that returns multiple duplicated values? I wanted to try reaching to the same result adding a little difficulty.
Facts:
home(peter, sanFrancisco, 1000).
home(ash, sanFrancisco, 100).
home(juan, sanFrancisco, 400).
home(juan, california, 700).
home(ash, california, 600).
home(peter, california, 500).
home(peter, vegas, 100).
home(ash, vegas, 80).
home(juan, vegas, 60).
townHomesTotalCost(sanFrancisco, 1500).
townHomesTotalCost(california, 1800).
townHomesTotalCost(vegas, 240).
Answer provided in the previous question was very helpful and I wanted to try something different to understand better logic programming. Lets say that instead of the home price, I want to compare by percentage. For the percentage I created this clause:
townHomeCostByPercentage(Name, Town, Percentage):-
home(Name, Town, Price),
townHomesTotalCost(Town, Total),
Percentage is round(((Price * 100) / Total)).
Getting the most expensive home in a town is such that no other home in that town is more expensive than it (Lets say I don't want to use the Price as an entry variable):
most_expensive(Name, Town):-
home( Name, Town, Price),
not((home( _, Town, P), P > Price)).
The second most expensive home in a town is such that is the most expensive among the homes which are not the most expensive home in that town:
second_most_expensive(Name, Town):-
most_expensive(Name, Town),
home(Name, Town, Price),
home(_, Town, Price2), Price < TopPrice,
not((home(_, Town, P), P < TopPrice, P > Price)).
I can't get why this is getting the same result as most_expensive(Name, Town)
And finally, using the percentage, return the Name but comparing percentage in that the most_expensive is < than the second_most_expensive + 20:
top_house_owner(Name) :-
most_expensive(Name, T),
townHomeCostByPercentage(Name, T, TopPercentage),
second_most_expensive(_, T),
townHomeCostByPercentage(_, T, Percentage),
TopPercentage < Percentage + 20.
This also returning the results name of most_expensive(Name, Town) and can't get why.

Retrieve data from database without printing

How do I retrieve data from the database to use it in a condition, but I don't want to print it the console.
Problem I am doing is to retrieve a child from a database whose parents age differ by 15 years.
This is the code I am using which works and prints the year of both parents.
family(person(_,_,date(_,_,Year1),_),
person(_,_,date(_,_,Year2),_),
[person(Name,Surname,_,_)|Y]), abs(Year1-Year2) >= 15.
Define a predicate rule (in a source file) using the query as its body. For example:
child_with_parents_age_gap(Gap, Name, Surname) :-
family(
person(_,_,date(_,_,Year1),_),
person(_,_,date(_,_,Year2),_),
[person(Name,Surname,_,_)| _]
),
abs(Year1-Year2) >= Gap.

How to findall for universal facts in prolog?

In Prolog I can write
child(martha,charlotte).
child(charlotte,caroline).
child(caroline,laura).
child(laura,rose).
descend(X,Y) :-
child(X,Y).
descend(X,Y) :-
child(X,Z),
descend(Z,Y).
And then write
?- findall(X,descend(martha,X),Z).
and get four solutions
Z = [charlotte,caroline,laura,rose]
But if I then add an universal fact
likes(X,pomegranate).
and try
?- findall(X,likes(X, pomegranate),Z).
I get:
Z = [_G17].
What is that _G17?
What do I need to change to get essentially all variables? ( since likes(X,pomegranate) should mean everything likes pomegranate... right?) :
Z = [martha,charlotte,caroline,laura,rose]
Two solutions. The clean solution is to have a table that lists all "things" in the universe you describe:
person(martha).
person(charlotte).
% etc
And then your "likes" would be rather:
person_likes(P, pomegranate) :-
person(P).
You can also try to hack around it:
person(P) :- child(P, _).
person(P) :- child(_, P).
But this is... unsatisfactory? Think about a relational database: you would have two tables:
CREATE TABLE person (
id INTEGER PRIMARY KEY, -- usually autogenerated
name TEXT NOT NULL
);
CREATE TABLE parent_child (
parent_id INTEGER NOT NULL,
child_id INTEGER NOT NULL,
FOREIGN KEY parent_id REFERENCES person(id),
FOREIGN KEY child_id REFERENCES person(id)
);
The only reason, as far as I am aware, why you don't do the exact same thing in Prolog, is that most introductory tutorials are trying to seduce you and avoid going into such details. And of course the Prolog "database" is not a true relational database (for example, argument position does matter!).
TL;DR You can't avoid thinking about Prolog's resolution strategy when using Prolog.

A prolog assignment which uses lists

I have an assignment that's driving me crazy.... Here's the assignment:
The following contacts for people in a company are kept as facts as the followings:
phones(joao, [home/217777777, mobile91/917777777]).
phones(maria, [work/218888888, mobile93/938888888, mobile91/918888888]).
phones(jose, [home/213333333, mobile91/914444444]).
Define predicates in Prolog that allow to answer the following question:
1) Which are the possible contacts availiable if you want to phone to any person in a group?
For example:
?- all_contacts([joao,jose],ListOfContacts).
ListOfContactss = [home/217777777, mobile91/917777777, home/213333333,mobile91/914444444]
What I've done is this:
all_contacts([],_):-[].
all_contactos([X|T],LIST):-phones(X,LIST),all_contacts(T,Y).
However if I do:
?- all_contactos([jose,maria],LIST_CONTACTS).
LIST_CONTACTS = [casa/213333333, movel91/914444444].
That is, I only get the contacts for the first person on the list.
Thanks for any help.
You can use the meta predicate findall to collect the phones for all contacts of an input list:
all_contacts(People, Contacts):-
findall(Contact,
( member(Person, People), % For each person
phones(Person, LContact), % get the list of contacts of person
member(Contact, LContact) % collect each contact from that list
), Contacts). % Finally gather all contacts in one list
For your example this yields:
all_contacts([jose,maria],LIST_CONTACTS).
LIST_CONTACTS = [home/213333333, mobile91/914444444, work/218888888, mobile93/938888888, mobile91/918888888].
If you don't want to use builtin predicate you can achieve the same thing using recursive predicates by iterating over all the people and then over every phone for each person, and building a list of contacts along the recursion:
all_contacts(People, Contacts):-
all_contacts(People, [], Contacts).
all_contacts([], Contacts, Contacts).
all_contacts([Person|People], Contacts, NContacts):-
phones(Person, LContacts),
all_contacts_person(LContacts, Contacts, MContacts),
all_contacts(People, MContacts, NContacts).
all_contacts_person([], Contacts, Contacts).
all_contacts_person([Contact|LContacts], Contacts, MContacts):-
all_contacts_person(LContacts, [Contact|Contacts], MContacts).

Resources