Prolog - 在谓词中搜索列表

时间:2017-05-28 11:24:20

标签: list prolog

我对他们所做的学生和运动有所谓,我想知道哪些学生做了特定的运动。我有这个音乐,但是如果我在列表中输入精确的运动,我只能得到结果,而我的查找谓词只能在列表中找到一项运动。我不知道怎么把它组合在一起用来找到做运动的学生:

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谓词,但不确定如何。

任何建议表示赞赏:)

1 个答案:

答案 0 :(得分:2)

找出哪些学生参与某项运动,您可以定义一个谓词:

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来获取排序列表(没有重复项,以防您碰巧有包含任何事实的事实):

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

请注意,在某些Prolog中,您可能必须明确包含要使用member/2的库,例如在Yap::- use_module(library(lists)).,而其他人则自动加载,例如SWI。

编辑:

关于您在评论中提出的问题,让我们开始观察student_sport/2一次产生一个答案。这是有意的,正如包含单词 student 的谓词名称所暗示的那样:它描述了学生和学生练习的特定运动之间的关系。这就是我使用findall/3setof/3添加示例查询的原因,以展示如何在列表中收集解决方案。您可以轻松定义谓词students_sport/2,该谓词描述特定运动与实践该运动的所有学生名单之间的关系:

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

关于体育 - 严肃,你可以选择一个原子来表示这种情况,比如none,然后像student_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).

这会产生以下结果:

   ?- 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']

最后,关于你对代码的假设与我写的完全一样:结构中有一个相似之处,即你的谓词find/1有第一个目标(sports/1)涉及一个列表,随后使用member/2检查该列表中的成员身份。 student_sport/2的第二个规则(或编辑前的单个规则)也有第一个目标(但不同的一个:does_sport/2)涉及一个列表,随后使用member/2来检查成员身份在那个清单中。这里的相似之处结束了。我提供的版本根本没有使用sports/1,而是does_sport/2中与特定学生相关的体育列表。请注意,find/1并未描述与学生的任何关联。此外,您的查询?- does_sport(X, find(soccer, L)).表示您似乎期望某种返回值。您可以将谓词视为返回truefalse的函数,但在编写Prolog时通常不太有用。参数find(soccer,L)没有像您期望的那样被调用,而是直接作为参数传递。因为你的事实不包含某些内容

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

您的查询失败。