Prolog: can we pass a fact as argument to another fact? - prolog

I have a rule where I have to check whether a person who works for a department also works for its college and the university. The sample knowledge base is the following:
university(xxx). /*the university*/
col(scienceAndMath,xxx). /*the college of the university*/
dept_col(biology,scienceAndMath). /*the department of the college*/
dept_faculty(michael,biology). /*the faculty member of the department*/
I have to make a rule, namely works_for(X,Y) to check that an individual who works for a department, also works for its college and the university. I am trying to do this in the following manner, but to no avail.
works_for(X,Y):-dept_faculty(X,Y).
works_for(X,Y):-dept_col(works_for(X,Y),Y).
/*also tried works_for(X,Y):-dept_col(dept_faculty(X,Y),Y)./*
For example, for the query works_for(michael,X)., the result should be following:
X = biology
X = scienceAndMath
How do I pass a fact as argument to another fact? At present, the answer of the query is the following:
X = biology
false.

Related

Prolog simple rules

Started learning Prolog 2 days ago and came across this problem, I'm trying to program both rules at the end but they don't seem to work correctly. What am I doing wrong?
% gender/2: identifies the gender of a person
gender(beto,male).
gender(willy,male).
gender(caonabo,male).
gender(haley,female).
gender(mary,female).
gender(yoli,female).
%friend/2 specifies the friendship between two persons
friend(beto,willy).
friend(willy,caonabo).
friend(willy,haley).
friend(haley,mary).
friend(haley,yoli).
% Rule to know if a person has any female friends
has_fFriend(person):- friend(person,friend),genero(friend,female).
% Rule to know if the person has any friends of it's same gender
homofriend(person):- friend(person,friend), gender(person,X) == gender(friend,X).

SWI-Prolog list result

I'm coding in prolog, but I have a issue. How can I make that the answer appears just once? for example I just want that "X = uni, X = uca, X = unam" but instead it just keep showing me the options repeatedly.
This is some of it:
is(uni, college).
is(uca, college).
is(unan, college).
is(computation, carrer).
In this part I'm assigning available places to the carrer
has(computation, available_places, 200).
and finally assigning the carrer to a college
offers(unan, computation).
offers(uni, computation).
offers(uca, computation).
and I make the query like this:
which(X):- is(X, college), is(Y, carrer), offers(X, Y),has(Y, available_places, Z), Z<300.
but the result as I said at the beggining, show me the names of the college repeadtedly. Any idea how to solve this? D:

Prolog check for predicate category

I have been working with Prolog since today, and wanted to create a simple test case. The basic idea was to have multiple sports defined, and it looks as follows:
soccer :- category(ball_sport),
check(has_11_players_per_team),
check(large_ball),
check(use_feet).
tennis :- category(ball_sport),
...
category(ball_sport) :-
check(has_a_ball).
Now I wanted to create a testcase, to see if both sports are of the ball_sport category, but have no idea to check these sports against eachother .. I thought it would be something like the code below, but it's obvious not. Is there an easy way to check these predicate categories? Thanks
both_ballsports(sport_one, sport_two) :-
has_category(sport_one, ball_sport),
has_category_sport_two, ball_sport).
It seems that first of all, you want to declaratively state attributes of a sport.
For example:
sport_attributes(soccer, [ball_sport,players(22),ball(large),use(feet)]).
sport_attributes(tennis, [ball_sport,players(2),players(4),ball(small),use(racket)]).
Note that I am relating sports to attributes. For comparison, the goals of the form check(X) you use above all seem to lack a critical argument, namely the actual sport for which they hold (or not). For example, the goal check(use_feet) either holds or not, but there is no means to qualify a unary predicate of this kind and state different facts for different sports.
Note the naming convention: We describe what each argument means, separated by underscores.
With this representation, both_ballsports/2 could look like this:
both_ballsports(Sport1, Sport2) :-
ballsport(Sport1),
ballsport(Sport2).
ballsport(Sport) :-
sport_attributes(Sport, As),
member(ball(_), As).
Sample query and answer:
?- both_ballsports(Sport1, Sport2).
Sport1 = Sport2, Sport2 = soccer ;
Sport1 = soccer,
Sport2 = tennis ;
Sport1 = tennis,
Sport2 = soccer ;
Sport1 = Sport2, Sport2 = tennis ;
false.
This can be used in all directions!

Prolog knowledge query

% A quiz team structure takes the form:
% team(Captain, Vice_captain, Regular_team_members).
% Captain and Vice_captain are player structures;
% Regular_team_members is a list of player structures.
% player structures take the form:
% player(First_name, Surname, details(Speciality,Recent_score)).
team(player(niall,elliott,details(history,11)),
player(michelle,cartwright,details(fashion,19)),
[player(peter,lawlor,details(science,12)),
player(louise,boyle,details(current_affairs,17))]).
I've been given the database above (I haven't copied over all the entries of people as it would be too long).
I've been asked to get the surname of any vice-captain whose team includes a captain or a regular team member whose speciality is science.
I can get the surname of the vice-captains using the code below but I can't return only those teams that include a captain or regular team members whose speciality is science. What would I need to add to do this?
part_two(Surname):-
team(_,player(_,Surname,_),_).
I've also been asked to also get the first name and the surname of any captain whose regular team members number more than one and who all have the same surnames.
This is my attempt so far:
part_three(First_name,Surname):-
team(Captain,_,Regular_team_members),
first_name(Captain,First_name),
surname(Captain,Surname),
Regular_team_members=[_,_|_].
I just need to exclude the details of those captains whose regular team members don't all have the same surname.
part_two(Surname):-
team(Captain, Vice_captain, Regular_team_members),
surname(Vice_captain, Surname),
member(Player, [Captain|Regular_team_members]),
specialty(Player, science).
% 'abstract data structures' accessors
surname(player(_First_name, Surname, _Details), Surname).
specialty(player(_First_name, _Surname, details(Speciality, _Recent_score)), Speciality).
Since you're going anyway to scan the Regular_team_members list, looking for appropriate constraint, you can get a simpler 'program' first 'joining' the Captain to other players.
You could change a little what you have already written as follows:
part_two(Surname):-
team(P,player(_,Surname,_),L),
( P=player(_,_,details(science,_)) -> true ; member(player(_,_,details(science,_)),L) ).
Example:
Database:
team(player(niall,elliott,details(history,11)),
player(michelle,cartwright,details(fashion,19)),
[player(peter,lawlor,details(history,12)),
player(louise,boyle,details(current_affairs,17))]).
team(player(niall1,elliott1,details(science,11)),
player(michelle1,cartwright1,details(fashion,19)),
[player(peter,lawlor,details(history,12)),
player(louise,boyle,details(current_affairs,17))]).
team(player(niall2,elliott2,details(history,11)),
player(michelle2,cartwright2,details(fashion,19)),
[player(peter,lawlor,details(science,12)),
player(louise,boyle,details(current_affairs,17))]).
team(player(niall3,elliott3,details(science,11)),
player(michelle3,cartwright3,details(fashion,19)),
[player(peter,lawlor,details(science,12)),
player(louise,boyle,details(current_affairs,17))]).
Now querying:
?- part_two(X).
X = cartwright1 ;
X = cartwright2 ;
X = cartwright3.

Prolog compound statement returning multiple variables

I'm super new to Prolog, like, my professor assigned us a program and just asked us to watch a couple youtube videos. No lecture.
So anyway, here's the issue:
I'm supposed to create a pharmacist software that looks up drug interactions.
When I enter a specific drug, then Drug-variable, and Interaction-variable, I get the first drug and interaction in the list (of like, 100 drugs that interact with temazepam):
?- interacts(temazepam,Drug,Interaction).
Drug = thalidomide,
Interaction = neutropenia .
Part 1) How can I get every drug and its interaction from, say, temazepam?
Partial program listed below [because I have 1609 lines of drug interactions listed]:
interacts(X,Y,Interaction):-
Drug(X),
Drug(Y),
Interaction.
Interaction:-
Drug(X),
Drug(Y).
interacts(gatifloxacin,zolpidem,attempted_suicide).
interacts(gatifloxacin,zolpidem,insomnia).
interacts(gatifloxacin,warfarin,cardiac_decompensation).
interacts(gatifloxacin,isosorbide-5-mononitrate,arteriosclerotic_heart_disease).
interacts(gatifloxacin,rosiglitazone,hyperglycaemia).
interacts(gatifloxacin,bortezomib,hyperglycaemia).
interacts(gatifloxacin,mometasone,asthma).
interacts(gatifloxacin,cisplatin,hyperglycaemia).
interacts(gatifloxacin,cisplatin,bone_marrow_failure).
interacts(gatifloxacin,montelukast,difficulty_breathing).
interacts(temazepam,thalidomide,neutropenia).
interacts(temazepam,thalidomide,thrombocytopenia).
interacts(temazepam,timolol,drowsiness).
interacts(temazepam,tizanidine,acid_reflux).
interacts(temazepam,tizanidine,heart_attack).
interacts(temazepam,tolterodine,amnesia).
Part 2) I need to be able to list an interaction and get back every drug that caused it.
I guess just the side-effect then all drug interactions listed would be better than listing drug1+sideEffect = drug2.
Example:
?- interacts(Drug,Drug,amnesia).
Part 3) I should be able to enter a single drug, and get everything with interactions and everything with no interactions.
Example:
?- interacts(valacyclovir,Drug,Interaction).
Drug = zolpidem,
Interaction = anxiety
But for everything
Excuse me for the edits!
Thanks so much in advance!
You can use the built-in predicate findall/3 for that:
drug_allinteractions(Drug,AI) :-
findall((D,I),interacts(Drug,D,I),AI).
The only goal of drug_allinteractions/2 is using findall/3 to query interacts/3 and put its second and third argument into the list AI as a tuple (D,I). Example query: Wich interacting drugs with what interaction-effect are known for gatifloxacin?:
?- drug_allinteractions(gatifloxacin,L).
L = [(zolpidem,attempted_suicide),(zolpidem,insomnia),(warfarin,cardiac_decompensation),(isosorbide-5-mononitrate,arteriosclerotic_heart_disease),(rosiglitazone,hyperglycaemia),(bortezomib,hyperglycaemia),(mometasone,asthma),(cisplatin,hyperglycaemia),(cisplatin,bone_marrow_failure),(montelukast,difficulty_breathing)]
Alternatively, if you just want to query interacts/3 and not write a program:
?- findall((D,I),interacts(gatifloxacin,D,I),AI).
AI = [(zolpidem,attempted_suicide),(zolpidem,insomnia),(warfarin,cardiac_decompensation),(isosorbide-5-mononitrate,arteriosclerotic_heart_disease),(rosiglitazone,hyperglycaemia),(bortezomib,hyperglycaemia),(mometasone,asthma),(cisplatin,hyperglycaemia),(cisplatin,bone_marrow_failure),(montelukast,difficulty_breathing)]
As for your added part 2): You can use findall on your original query:
?- findall((D1,D2),interacts(D1,D2,amnesia),AI).
AI = [(temazepam,tolterodine)]
Note, that unlike in your example I wrote two different variables D1 and D2 for the drugs, otherwise you are asking which drug has the interaction-effect amnesia with itself.
Considering your added part 3) I'm not entirely sure what you want. Your query reads: "Show me all drugs that interact with valacyclovir plus the associated effect". That is basically the same as your very first query, just for a different drug. You can query for all drugs in the relation interacts/3 interactively without showing the interacting drugs and the effects by:
?- interacts(D,_,_).
D = gatifloxacin ? ;
...
Or query for an entire list without duplicates by using setof/3:
?- setof(D1,D2^I^interacts(D1,D2,I),AI).
AI = [gatifloxacin,temazepam]
If you, however, try to find a list of drugs that are not interacting with a given drug, you can write a predicate, say drug_noninteractingdrug/2...
:- use_module(library(lists)).
drug_noninteractingdrug(D,NID) :-
dif(D,NID), % D and NID are different
setof(D2,D^interacts(D,D2,_),L), % L ... all drugs interacting with D
interacts(NID,_,_), % NID ... drug...
\+member(NID,L). % ... that is not in L
... and query this using setof/3:
?- setof(NID,drug_noninteractingdrug(gatifloxacin,NID),NIDs).
NIDs = [temazepam]
With your given minimal example this query of course only yields one drug. Note that you need to include library(lists) for the predicate member/2.

Resources