0

我需要根据我拥有的事实构建一个列表。例如,我有一个这样的课程列表:

    attend(student1,c1).
    attend(student1,c2).
    attend(student2,c1).
    attend(student2,c3).

现在我想要一个谓词 courselist/2 ,它返回给定学生的课程列表。当然,每门课程都应该只在这个列表中出现一次。我不能使用像 findall 这样的内置谓词,但我可以使用成员或附加。到目前为止,我有这样的事情:

    courselist(S,R) :- attend(S,C), member(C,R), courselist(S,R).
    courselist(S,R) :- attend(S,C), append([C],L,R), courselist(S,R).

我知道那是错误的,但我不知道如何在不陷入无限循环的情况下找到所有事实。

4

1 回答 1

2

这是一个您不能使用的愚蠢限制findall/3,因为它是解决此类问题的自然方法。您可以像这样手动执行此操作:

student_courses(Student, Courses) :-
        student_courses(Student, [], Courses).

student_courses(S, Cs0, Cs) :-
        (   attend(S, C), \+ member(C, Cs0) ->
            student_courses(S, [C|Cs0], Cs)
        ;   Cs = Cs0
        ).

示例查询:

?- student_courses(student2, Cs).
Cs = [c3, c1].

请注意,这不是真正的关系,因为此特定解决方案不会出现在以下更一般的查询中:

?- student_courses(Student, Cs).
Student = student1,
Cs = [c2, c1].

我把它作为练习留给你,让你以最一般的查询产生所有正确结果的方式来实现它。还要注意更具可读性和相关性的谓词名称。

于 2013-04-21T15:36:49.940 回答