Демо Пролог: Поиск квартиры по каталогу
В этой демонстрации из каталога квартир, в котором указаны цена, количество комнат и ориентация, проводится поиск оптимального объекта по заданным критериям.
Показать список квартир
Сначала помещаем каталог в память и добавляем программу, которая позволяет просматривать список содержащихся в нем продуктов.
app(appart1, sud, 3, 60).
app(appart2, nord, 5, 80).
app(appart3, sud, 4, 70).
app(appart4, sud, 6, 90).
app(appart5, sud, 4, 100).
app(appart6, ouest, 8, 50).
catalogue :-
write('Catalogue...\n'),
forall(app(X,O,T,P), format("Code ~a orientation ~a T~D prix ~D.000 ~n", [X, O, T, P])).
Функция пролога forall является функцией объединения. Первый термин - это условие, это условие сталкивается с каждым предикатом типа «app» в памяти. Второй термин - действие, оно выполняется для каждого экземпляра, который заполняет условность.
Поскольку значения предиката не назначаются, условие проверяется для всех предикатов базы. Если бы в качестве второго значения дали «юг», то условие проверяли бы только для квартир с «южной» ориентацией.
Поэтому для отображения списка всех квартир, независимо от их ориентации, используется это условие без заранее определенного значения.
Выбрать квартиры по критериям
Хочется выбрать квартиры с определенной ориентацией и максимальной заданной ценой.
Если бы речь шла только о поиске квартир с определенной ориентацией и ценой, это было бы просто, мы бы использовали предыдущее правило каталога с двумя параметрами:
catalogue(O,P) :-
write('Catalogue...\n'),
forall(app(X,O,T,P), format("Code ~a T~D ~n", [X, T])).
И было бы сделано такое ходатайство, как, например:
catalogue(sud, 70).
Но мы должны сравнить цены с предельным значением, и поэтому код будет немного сложнее.
Функция findall prolog позволяет создать список элементов, удовлетворяющих условиям.
findall(element, condition impliquant l'élément, liste)
Условие в нашем случае - иметь ориентацию, равную заданному значению O, и цену P ниже данной цены PMax.
candidats(O, PMax) :-
findall(X, (app(X,O,_,P), P =< PMax), L),
write('\nCandidats au catalogue:\n'),
dispList(L).
Мы группируем в скобках app (X,O,_,P) и сравнение цены P = <PMax, чтобы сформировать условие в один параметр .
Этот код возвращает список L всех элементов X, удовлетворяющих условию. Посмотрим, как показать этот список.
Показать список в Prolog
Аргумент формы [A 'B] означает первый элемент списка, за которым следуют все остальные элементы. Называется правило со списком L в параметре и пролог разбивает этот список на две части.
Удобно перечислять содержимое списка рекурсией. Просто замените параметр [A 'B] на B, когда правило ссылается само на себя.
dispList([A|B]) :-
(app(X,_,T,P), X = A),format('~w T~D ~D.000 euros ~n', [X, T, P]),
dispList(B).
Правило dispList рекурсивно вызывает себя, каждый раз заменяя список второй частью B, которая не содержит первого элемента. Первый элемент А рассматривается в правиле.
Наше правило объединяет элемент А с предикатом приложения, одним из значений которого является этот элемент А. Функция формата отображает значения найденного предиката .
Найти самую большую квартиру, которая соответствует критериям
Мы ищем квартиру X с количеством комнат T. Мы хотим, чтобы количество комнат было как можно больше. Добавляются другие условия.
Недоказанный оператор\+ возвращает истину, если его аргумент не доказан, и ложность, если он доказан.
\+ (terme)
Смысл здесь в том, чтобы получить унификацию последовательных значений, назначив максимальное значение Т.
Переменные X и T не назначаются при вызове правила, в отличие от ORT и PMax. Они назначаются каждый раз, когда в предикате приложения значение T2 превышает T и два других критерия соблюдаются.
plusGrand(X, ORT, PMax) :-
app(X, _, T, _),
\+ (app(_, O, T2, P), (T2 > T, O = ORT, P =< PMax)).
Недоказуемая формула ищет предикат app или значение O равно заданному значению ORT, значение P меньше или равно заданному значению PMax, а значение T2 больше значения T уже найденной квартиры.
Пока есть значение T2 выше T, формула доказана, происходит сбой и продолжается объединение в поисках решения.
Как только T2 достигает максимального значения, получается разрешение, и возвращаешься в точку вызова правила с назначенными переменными X и T. Квартира, соответствующая критериям, найдена.
Поиск квартиры, полное демо
app(appart1, sud, 3, 60).
app(appart2, nord, 5, 80).
app(appart3, sud, 4, 70).
app(appart4, sud, 6, 90).
app(appart5, sud, 4, 100).
app(appart6, ouest, 8, 50).
catalogue :-
write('Catalogue...\n'),
forall(app(X,O,T,P), format("Code ~a orientation ~a T~D prix ~D.000 ~n", [X, O, T, P])).
dispList([]).
dispList([A|B]) :-
(app(X,_,T,P), X = A),format('~w T~D ~D.000 euros ~n', [X, T, P]),
dispList(B).
plusGrand(X, ORT, PMax) :-
app(X, _, T, _),
\+ (app(_, O, T2, P), (T2 > T, O = ORT, P =< PMax)).
meilleur(O,P) :-
plusGrand(X, O, P),
write('\nPlus grand: '),
write(X).
candidats(O, PMax) :-
findall(X, (app(X,O,_,P), P =< PMax), L),
write('\nCandidats au catalogue:\n'),
dispList(L).
recherche(O, P):-
meilleur(O, P);
write('Rien au catalogue.').
test1 :- candidats(sud, 80).
test2 :- recherche(sud, 80).
Pour utiliser ce programme, utilisez la commande consult de la console prolog. Puis tapez:
catalog.
test1.
test2.
Pour respectivement, afficher la liste de tous les appartements, la liste des appartements orientés sud et de prix inférieur à 80, enfin le plus grand parmi ceux qui respectent ces critères.
Vous pouvez aussi donner vos propres critères, comme dans cet exemple:
recherche(nord, 100).
Vous pouvez télécharger le code source.