Найти все решения в прологе

В прологе я пытаюсь объединить все действительные пары потребностей с ресурсами

needs([ece2090,1,m,13,16]).
needs([ece3520,1,tu,11,14]).
needs([ece4420,1,w,13,16]).

resources([joel, [ece2090,ece2010,ece3520,ece4420],[[m,13,16]]]).
resources([sam, [ece2010,ece4420],[]]).
resources([pete, [ece3520],[[w,13,16]]]).

используя эту формулу

make_bid([Class,Sect,Day,Ts,Te],[Name,Cap,Unavail],[Class,Sect,Day,Ts,Te,Name,_]) :-
no_conflict_all_unavailable(Day,Ts,Te,Unavail),
course_capable(Class,Cap),
writef('%w %w %w\n',[Class,Sect,Name]),
fail.

и запустить этот тест.

test(Listing) :- needs(N), resources(R), make_bid(N,R,Listing).

Смысл этой части программы состоит в том, чтобы соединить каждый класс с учителем, у которого есть квалификация, чтобы преподавать класс, и который не будет недоступен в течение этого времени. Это должно дать список.

?- test(Listing).
ece3520 1 joel
ece3520 1 pete
ece4420 1 joel
ece4420 1 sam
false.

При запуске выше генерируется. Это правильно, но это в формате, который мне бесполезен, поскольку мне нужно, чтобы он был отдельной переменной для дальнейших вычислений. Тогда решение - использовать bagof или findall, верно?

Поэтому я удаляю предложение fail из основной части программы, а затем изменяю тест на этот

test(Bag) :- needs(N), resources(R), bagof(Listing,make_bid(N,R,Listing),Bag).

но это порождает это

ece3520 1 joel
Bag = [[ece3520, 1, tu, 11, 14, joel, _G4310]] 

Если вы присмотритесь, вы увидите, что в конце нет периода, а также отсутствует утверждение "истина / ложь". Это привело бы к мысли, что это бесконечный цикл. Однако это не так, поскольку матрица Bag полностью сформирована, и я могу просто напечатать "." завершить программу (вместо того, чтобы прервать ее).

Он только генерирует первое действительное решение. Почему это происходит?

1 ответ

Решение

Вы структурировали свой test предикат так, чтобы bagof/3 вызывается для каждого экземпляра комбинации needs(N) а также resources(R) и поэтому он собирает каждый результат make_bid в своем собственном bagof/3 результат:

ece3520 1 joel
Bag = [[ece3520, 1, tu, 11, 14, joel, _G4310]]

Первая строка write это в make_bid сказуемое. Вторая строка Bag результат для одного запроса к make_bid за одну пару needs/resources, Последний аргумент в списке, _G4310происходит потому, что ваш предикат использует _ и это анонимно (никогда не используется / создается).

Ваш текущий make_bid предназначен для записи результатов в цикле, а не для их создания в нескольких возвратах. Так что это можно изменить на:

make_bid([Class, Sect, Day, Ts, Te], [Name, Cap, Unavail], [Class, Sect, Day, Ts, Te, Name, _]) :-
    no_conflict_all_unavailable(Day, Ts, Te, Unavail),
    course_capable(Class, Cap).

(ПРИМЕЧАНИЕ: я не уверен, почему у вас есть _ в конце 3-го списка аргумента. Что это представляет?)

Если вы хотите собрать весь результат в один список, вы можете использовать findall/3:

findall([Class, Sect, Name], (needs(N), resources(R), make_bid(N, R, [Class, Sect, _, _, _, Name, _]), Listings).

Это соберет список элементов, которые выглядят так, [Class, Sect, Name], Вы могли бы использовать bagof/3 здесь, но вам понадобится экзистенциальный квантификатор для переменных в make_bid/3 позвони, что не хочешь связывать.

Если бы вы хотели весь Listing список, то:

findall(L, (needs(N), resources(R), make_bid(N, R, L)), Listings).

Но каждый элемент Listings будет список, последний элемент которого является анонимной переменной, так как это make_bid/3 структурирован.

Другие вопросы по тегам