List Prolog-在谓词中搜索列表

List Prolog-在谓词中搜索列表,list,prolog,List,Prolog,我有学生和他们从事的体育活动的谓词,我想找出哪些学生从事某项特定的体育活动。到目前为止,我已经有了这一点,但我只能在列表中输入确切的运动项目时才能得到结果,而我的find谓词只能在列表中查找运动项目。我不知道如何将其组合起来,以找到从事1项运动的学生: student('Quinton Tarentino', male, 12). student('Tom Hanks', male, 9). student('Ed Harris', male, 11). does_sport('Quinton

我有学生和他们从事的体育活动的谓词,我想找出哪些学生从事某项特定的体育活动。到目前为止,我已经有了这一点,但我只能在列表中输入确切的运动项目时才能得到结果,而我的find谓词只能在列表中查找运动项目。我不知道如何将其组合起来,以找到从事1项运动的学生:

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).
我试过这样的方法:

?- does_sport(X, find(soccer, L)).
这只是返回false。我知道我需要将我的运动列表链接到does_sports谓词,但不确定如何链接

任何建议都值得赞赏:)

要找出哪些学生从事特定的运动,您可以定义如下谓词:

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
然后,您可以按照您在问题中的意图,查询例如足球,如:

   ?- student_sport(St,soccer).
St = 'Quintin Tarentino' ? ;
no
另一方面,曲棍球产生两种结果:

   ?- student_sport(St,hockey).
St = 'Quintin Tarentino' ? ;
St = 'Ed Harris' ? ;
no
如果你想有一份参加曲棍球比赛的学生名单,你可以使用
findall/3
如下:

   ?- findall(St,student_sport(St,hockey),L).
L = ['Quintin Tarentino','Ed Harris']
或者,
setof/3
获得一个排序列表(如果您碰巧有包含任何内容的事实,则没有重复项):

请注意,在某些序言中,您可能必须明确包含一个库来使用
成员/2
,例如在Yap:
:-use_模块(库(列表))。
,而其他的则自动加载,例如SWI

编辑: 关于您在评论中提出的问题,让我们从您的观察开始,即
student_sport/2
一次给出一个答案。这是有意的,正如包含单词student的单数谓语名所暗示的那样:它描述了一个学生和一个学生所从事的特定运动之间的关系。这就是为什么我添加了带有
findall/3
setof/3
的示例查询,以展示如何在列表中收集解决方案。您可以轻松定义一个谓词
students\u sport/2
,该谓词描述特定运动与所有练习该运动的学生列表之间的关系:

students_sport(L,Sp) :-
   setof(St,student_sport(St,Sp),L).
关于运动紧缩,您可以选择一个原子来表示该情况,例如
none
,然后根据
student\u sport/2
添加相应的规则,如下所示:

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).
最后,关于你的代码与我写的代码完全相同的假设:在结构上有一个相似性,即你的谓词
find/1
有一个第一个目标(
sports/1
),包括一个列表,然后使用
member/2
检查该列表中的成员身份。
student_sport/2
的第二条规则(或编辑前的单一规则)也有第一个目标(但另一个目标是:
does_sport/2
),包括一个列表,然后使用
member/2
检查该列表中的成员资格。相似之处到此为止。我提供的版本根本不使用
sports/1
而是与特定学生相关的体育项目列表(位于
do sport/2
)。请注意,
find/1
没有描述与学生的任何联系。此外,您的查询
?-dos_sport(X,find(soccer,L))。
表明您似乎期望某种返回值。您可以将谓词视为返回
true
false
的函数,但在编写Prolog时,这通常不是很有帮助。参数
find(soccer,L)
并不像您期望的那样被调用,而是作为一个参数传递。既然你的事实不包括

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

您的查询失败。

这是肯定的。感谢助教、findall和setof work 100%,但学生体育(圣,曲棍球)。每次只返回一个学生,即使我有多个学生在做这项运动,我(认为)我的代码和你在这里写的一模一样。此外,我不知道如何表示一个空列表,例如“汤姆·汉克斯”不做运动。如果我只通过blank或“”或[],我只会得到false。@ildsarria:我更新了我的答案,以解决您在评论中提出的问题。
   ?- 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']
does_sport(*SomeStudentHere*, find(soccer,L)).