2013-04-21 6 views
0

Мне нужно построить список, основанный на фактах, которые у меня есть. Например, у меня есть список курсов, как это:Добавить факт в список, если он еще не находится в

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

Теперь я хочу, чтобы иметь предикат courselist/2, который возвращает список курсов для данного студента. Конечно, каждый курс должен быть в этом списке только один раз. Я не могу использовать встроенные предикаты, такие как findall, но я могу использовать member или append. До сих пор у меня есть что-то вроде этого:

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). 

, и я знаю, что это неправильно, но я не знаю, как найти все факты, не вдаваясь в бесконечный цикл.

ответ

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]. 

Я оставляю это как упражнение для вас, чтобы реализовать ее таким образом, что наиболее общий запрос дает все правильные результаты. Также обратите внимание на более читаемые и реляционные имена предикатов.

Смежные вопросы