简体   繁体   中英

Prolog - searching a list inside a predicate

I have predicates of students and sports they do, and I want to find out which students do a particular sport. I have this sofar, but i can only get results if I enter exact sports in a list , and my find predicate works only to find a sport in a list. I don't know how to put it together to use to find students that do 1 sport:

student('Quinton Tarentino', male, 12).
student('Tom Hanks', male, 9).
student('Ed Harris', male, 11).

does_sport('Quinton Tarentino', [soccer, hockey, cricket]).
does_sport('Tom Hanks', []).
does_sport('Ed Harris', [hockey, swimming]).

sports([soccer, hockey, swimming, cricket, netball]).

find(X) :- sports(L), member(X, L).

I tried things like:

?- does_sport(X, find(soccer, L)).

This just returns false. I know I need to link my sports list to the does_sports predicate but not sure how.

Any advice appreciated :)

To find out which students do a particular sport , you could define a predicate like so:

student_sport(St,Sp) :-
   does_sport(St,L),      % L is a list of sports student St does
   member(Sp,L).          % Sp is a member of list L

Then you can query for eg soccer, as you seem to intend in your question, like so:

   ?- student_sport(St,soccer).
St = 'Quintin Tarentino' ? ;
no

Hockey on the other hand yields two results:

   ?- student_sport(St,hockey).
St = 'Quintin Tarentino' ? ;
St = 'Ed Harris' ? ;
no

If you want to have a list of students doing hockey instead, you can use findall/3 like so:

   ?- findall(St,student_sport(St,hockey),L).
L = ['Quintin Tarentino','Ed Harris']

Or alternatively setof/3 to get a sorted list (without duplicates, in case you happened to have facts that contain any):

   ?- setof(St,student_sport(St,hockey),L).
L = ['Ed Harris','Quintin Tarentino']

Note that in some Prologs you might have to explicitly include a library to use member/2 , eg in Yap: :- use_module(library(lists)). , while others autoload it, eg SWI.

EDIT:

Concerning the issues you raised in your comment, let's maybe start with your observation that student_sport/2 produces the answers one at a time. That is intentional, as suggested by the predicate name that contains the word student in singular: It describes a relation between a student and a particular sport that very student practices. That's why I added the example queries with findall/3 and setof/3 , to show ways how you can collect solutions in a list. You can easily define a predicate students_sport/2 that describes a relation between a particular sport and a list of all students who practice it:

students_sport(L,Sp) :-
   setof(St,student_sport(St,Sp),L).

Concerning the sports-austere, you can choose an atom to denote that case, say none and then add an according rule to student_sport/2 like so:

student_sport(St,none) :-   % <- rule for the sports-austere
   does_sport(St,[]).       % <- succeeds if the student does no sport
student_sport(St,Sp) :-
   does_sport(St,L),
   member(Sp,L).

This yields the following results:

   ?- student_sport(St,none).
St = 'Tom Hanks' ? ;
no

   ?- students_sport(St,none).
St = ['Tom Hanks']

   ?- students_sport(St,hockey).
St = ['Ed Harris','Quintin Tarentino']

   ?- students_sport(St,Sp).
Sp = cricket,
St = ['Quintin Tarentino'] ? ;
Sp = hockey,
St = ['Ed Harris','Quintin Tarentino'] ? ;
Sp = none,
St = ['Tom Hanks'] ? ;
Sp = soccer,
St = ['Quintin Tarentino'] ? ;
Sp = swimming,
St = ['Ed Harris']

And finally, concerning your assumption of your code being exactly as I wrote it: There is a similarity in structure, namely your predicate find/1 having a first goal ( sports/1 ) involving a list and subsequently using member/2 to check for membership in that list. The second rule (or single rule before the edit) of student_sport/2 is also having a first goal (but a different one: does_sport/2 ) involving a list and subsequently using member/2 to check for membership in that list. Here the similarities end. The version I provided is not using sports/1 at all but rather the list of sports associated with a particular student in does_sport/2 . Note that find/1 does not describe any connection to students whatsoever. Furthermore your query ?- does_sport(X, find(soccer, L)). indicates that you seem to expect some sort of return value. You can regard predicates as functions returning true or false but that is usually not very helpful when programming Prolog. The argument find(soccer,L) is not being called as you seem to expect, but literally passed as an argument. And since your facts do not include something along the lines of

does_sport(*SomeStudentHere*, find(soccer,L)).

your query fails.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM