SWI-Prolog: Как остановить предикат, когда список пуст?(предикат включен) - PullRequest
2 голосов
/ 14 марта 2019
course(cmput325).
course(cmput175).
course(cmput201).
course(cmput204).
prerequisite(cmput204, cmput325).
prerequisite(cmput175, cmput201).
prerequisite(cmput175, cmput204).

Мне нужно написать новый предикат, который будет

can_take(+L,?C).

Определение:

L - это заданный список курсов, которые студент уже прошел.Если также задан C, то предикат должен проверить, есть ли у студента все необходимые курсы для C. Если C является переменной, то при обратном отслеживании предикат должен производить один курс за раз, который студент может пройти сейчас.Курсы могут быть в любом порядке, но каждый курс должен быть создан только один раз, и вы не должны возвращать какие-либо курсы, которые студент уже прошел.

Пример:

?- findall(C, can_take([cmput175], C), L).
should return

L = [cmput201, cmput204].

Вот мойПредикат:

can_take(L,C) :- prerequisite(L,C).
can_take([L|List],C) :- prerequisite(L,C),can_take(List,C).

Этот предикат не вернул правильный результат, а просто вернул false.Я думаю, что это потому, что я не определил условие, когда L пусто, однако, если я попытался добавить L \ == [] в любой из них.Это все еще дало мне ошибку ... что я должен сделать, чтобы этот предикат остановился и дал мне результат?

------- update -------

pre(X,C) :- prerequisite(X,C).   
pre(X,C) :- prerequisite(X,Y), pre(Y,C).

pre2(C,L) :- findall(L1,pre(L1,C),L).

required(C,L) :- pre2(C,L1),sort(L1,L).

can_take([],_).
can_take(L,C) :- required(C,L).
can_take([L|List],C) :- prerequisite(L,C),can_take(List,C).

Вот мой тест кода:

?- required(cmput325,L).
L = [cmput175, cmput204].

?- required(cmput204,L).
L = [cmput175].

?- can_take([cmput175],X).
X = cmput201 ;
X = cmput204 ;

?- findall(C, can_take([cmput175], C), L).
L = [cmput201, cmput204].


?- can_take([cmput204],cmput325).
false. (this one is OK)

?- can_take([cmput175,cmput204],cmput325).
true ;
false. (this one is OK)

?- can_take([cmput175],cmput204).
true ;
true ;
false.

последний не в порядке, потому что я не хочу, чтобы он возвращал два истинных утверждения ... так что я хочу просто дать ему остановиться, когда либовторая или последняя строка возвращает true.Для моего задания я не могу использовать оператор cut !, есть ли другой способ сделать это?

1 Ответ

3 голосов
/ 15 марта 2019

(Я предполагаю, что вы можете пройти курс второй раз, даже если вы уже прошли его. По крайней мере, это те правила, которые я знаю.)

Вы можете пройти курспри условии, что вы уже прошли все необходимые курсы.

В Прологе нет прямого "всего".Но вы можете сформулировать это по-разному

Вы можете пройти курс, если нет обязательного курса, который вы еще не прошли.

can_take(Takens, Next) :-
    course(Next),
    iwhen( ground(Takens), 
           \+ ( prerequisite(Required, Next), \+ member(Required, Takens) ) ).

Это использует iwhen/2 для защиты от случаев, когда Takens не полностью создан.

Обратите внимание, что в ваших примерах есть небольшая разница:

?- findall(C, can_take([cmput175], C), L).
L = [cmput175, cmput201, cmput204].
%    ^^^^^^^^

Отказ от ответственности
Ваша проблема по своей сути немонотонна: добавляя дополнительные факты для требований, вы сокращаете количество возможных курсов, которые вы можете пройти.Как новичок, скорее придерживайтесь проблем, которые являются монотонными по своей природе.Именно на этой стороне Prolog действительно превосходит.

...