0

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).
false
  • 10,264
  • 13
  • 101
  • 209
  • 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 Jul 11 '17 at 19:36
  • If you don't have any redundancy issues in results from `student/4` queries, you could use `findall(N, students(N, _, cricket, _), L).` – lurker Jul 11 '17 at 19:44
  • 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 Jul 11 '17 at 19:49
  • Please show your facts. – tas Jul 11 '17 at 19:54
  • 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 Jul 11 '17 at 20:09

1 Answers1

1

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]
tas
  • 8,100
  • 3
  • 14
  • 22