0
votes

How do I query database facts with 3 or more attributes in Prolog using bagof, setof. An example I have a defined a database students(name, grade,sport,gender). I want find a list of students that play a particular sport, say cricket. My current query

sport_list(L):- 
        bagof(S,N^G^D^students(N,G,S,D),L),
           S = cricket.

student(patash,5,rugby,male).
student(naomi,3,netball,female).
student(lepo,6,_,male).
student(diamal,4,cricket,male).
student(bonga,5,chess,female).
student(imi,6,cricket,male).
student(ayanda,3,_,female).
1
The documentation for setof/3 and bagof/3 indicate that the first argument is the term you wish to collect. So in this case, that would be the student name variable. Second argument should be the condition, and the 3rd argument is the list to collect into. So: setof(N, G^D^students(N, G, cricket, D), L). Your bagof call collects sports into L, then attempts to unify S with cricket. No collection of names occurs.lurker
If you don't have any redundancy issues in results from student/4 queries, you could use findall(N, students(N, _, cricket, _), L).lurker
Thanks for the answer but how do I exclude the names of students not playing a sport? When I tried that it returned students who did not have a sport.user8291645
Please show your facts.tas
Change the condition (2nd argument) in your bagof to exclude the case where S is a variable. See var/1 documentation.Try some things. Don't make us do all of your work for you. :) Easier, use an atom instead of an anonymous variable (_) to mean "no sport". Why not use none or 'no sport'? That would solve the problem without additional logic. The anonymous variable is going to match anything.lurker

1 Answers

1
votes

You could model your knowledge base such that the third argument is none for unathletic students instead of _:

student(lepo,6,none,male).
student(ayanda,3,none,female).

Then you can define a predicate that describes atheletic students as being those who do not have none as sport:

athletic(S) :-
   dif(X,none),
   student(S,_,X,_).

Subsequently use athletic/1 in the single goal of sport_list/1:

sport_list(L):- 
   bagof(S,athletic(S),L).

That yields the desired result:

   ?- sport_list(L).
L = [patash,naomi,diamal,bonga,imi]