Использование составных термов
В Прологе функциональный терм или предикат можно рассматривать как структуру данных, подобную записи в языке Паскаль. Терм, представляющий совокупность термов, называется составным термом. Предикаты, записанные в виде составного терма, называются составной структурой данных. Составные структуры данных в Турбо-Прологе объявляются в разделе domains. Если термы структуры относятся к одному и тому же типу доменов, то этот объект называется однодоменной структурой данных. Если термы структуры относятся к разным типам доменов, то такая структура данных называется многодоменной структурой данных. Использование доменной структуры упрощает структуру предиката.
Пример 12: Необходимо создать БД, содержащую сведения о книгах из личной библиотеки. Зададим составной терм с именем personal_library, имеющим следующую структуру: personal_library= book (title, author, publisher, year), и предикат collection (collector, personal_library). Терм book называется функтором структуры данных. Пример программы, использующей составные термы для описания личной библиотеки и поиска информации о книгах, напечатанных в 1990 году, выглядит следующим образом:
domains
collector, title, author, publisher = symbol
year = integer
personal_library = book (title, author, publisher, year)
predicates
collection (collector, personal_library)
clauses
collection (irina, book («Using Turbo Prolog», «Yin with Solomon», »Moscow, World», 1993)).
collection (petr, book («The art of Prolog», «Sterling with Shapiro», »Moscow, World», 1990)).
collection (anna, book («Prolog: a relation language and its applications», «John Malpas», »Moscow, Science», 1990)).
goal
collection (X, book( Y,_, _, 1990)
Представление данных часто требует наличия большого числа структур. В Прологе эти структуры должны быть описаны. Для более компактного описания структур данных в Прологе предлагается использование альтернативных описаний доменов.
Пример 13: Необходимо создать БД, содержащую сведения о книгах и аудиозаписях из личной библиотеки.
domains
person, title, author, artist, album, type = symbol
thing = book (title, author); record (artist, album, type)
predicates
owns (person, thing)
clauses
owns (irina, book («Using Turbo Prolog», «Yin with Solomon»)).
owns (petr, book («The art of Prolog», «Sterling with Shapiro»)).
owns (anna, book («Prolog: a relation language and its applications», «John Malpas»)).
owns (irina, record («Elton John», «Ice Fair», «popular»)).
owns (petr, record («Benny Goodman», «The King of Swing», »jazz»)).
owns (anna record («Madonna», «Madonna», «popular»»)).
goal
owns (X, record(_, _, «jazz»)
Пример 14:
Создать базу данных о заданной предметной области в виде множества фактов языка Пролог (не менее 5 фактов). Информацию о каждом компоненте БД представить в виде структуры. Разработать набор предикатов, осуществляющих взаимодействие с БД, при помощи которых можно реализовать все типы запросов, приведенные в варианте задания.
Предметная область – база данных товаров мебельного магазина. Каждый магазин может быть описан структурой: название магазина, адрес, фамилия директора, список имеющихся товаров. Каждый товар может быть описан структурой: название товара, цена, страна-производитель, список имеющихся расцветок.
Реализовать следующие запросы:
1. Найти адрес магазина, у которого директором является человек с заданной фамилией.
2. Найти названия всех магазинов, продающих заданный товар.
3. Найти название товара, имеющего максимальную цену.
В приведенном ниже примере используются следующие домены:
list_colours - список расцветок, list_products - список имеющихся товаров, name_shop - название магазина, address –адрес магазина, chief, -фамилия директора, name_product – название товара, country - страна-производитель, price – цена.
shop – предикат, описывающий заданную предметную область, q1,q2, q3 – предикаты, реализующие первый, второй и третий запрос соответственно, q21, q31–вспомогательныепредикаты для второго и третьего запросов, max – динамический предикат, необходимый для третьего запроса.
domains
list_colours = symbol*
list_products = product*
name_shop, address, chief, name_product, country = symbol
price =real
product = prod (name_product, price, country, list_colours)
facts
max(name_product, price)
predicates
shop (name_shop, address, chief, list_products)
q1(chief)
q2(name_product)
q21(name_product, list_products)
q3
q31(list_products)
clauses
shop("Company1","Debenko_5","Ivanov",[prod(table,3000,"Italy",[white, red, black]),prod(chair,4000,"Japan",[brown, grey])]).
shop("Company2","S.Lazo_4","Petrov",[prod(sofa,9000,"China",[brown, black]),prod(chair,5000,"England",[red, grey])]).
shop("Company3","Sadovaya_3","Sidorov",[prod(sofa,19000,"Mexico", [black, white])]).
shop("Company4","Dachnaya_2","Orlov",[prod(bookcase,7000,"Russia", [brown, black]),prod(table,6000,"Spain",[red,grey])]).
shop("Company5","Pobeda_1","Galkin",[prod(bed,5000,"China",[brown, black]),prod(arm_chair,21000,"Japan",[red, grey])]).
% первый запрос: обращаемся к предикату shop, проверяем, совпадает ли фамилия директора данного магазина с заданной фамилией, для этого используется одна и та же переменная F, в случае совпадения печатаем адрес магазина A.
q1(F):-shop (_,A,F,_),write(A),nl.
% второй запрос: обращаемся к предикату shop, извлекаем название магазина N и список имеющихся товаров L, вызываем вспомогательный предикат q21, которому передаем название заданного товара P и список имеющихся товаров L, q21 будет истинен, если заданный товар есть в списке имеющихся товаров, в этом случае выводим на экран название магазина.
q2(P):-shop(N,_,_,L),q21(P,L),write(N),nl,fail.
q21(H,[H1|_]):-H1=prod(H,_,_,_).
q21(H,[_|T]):-q21(H,T).
% третий запрос: записываем в динамический предикат max любое название товара, например, a и его цену 0, так как мы ищем название товара, имеющего максимальную цену, соответственно первоначальная цена должна быть маленькая, чтобы обязательно был товар с более высокой ценой, обращаемся к предикату shop, извлекаем список имеющихся товаров L, вызываем вспомогательный предикат q31, которому передаем список имеющихся товаров L, q31 проверяет, имеет ли очередной товар из списка имеющихся товаров цену, более высокую, чем цена, записанная в предикате max, в этом случае предикатом retract удаляем старые название товара и цену, предикатом assert записываем новое название товара и цену, иначе просто переходим к следующему товару.
max(a,0).
q3:-shop(_,_,_,L),q31(L),fail.
q31([]).
q31([H1|T]):-H1=prod(H,P,_,_), max(A,B), P>B, retract(max(A,B)), assert(max(H,P)), q31(T).
q31([H1|T]):-H1=prod(_,P,_,_),max(_,B),P<=B,q31(T).
goal
% вызываем каждый запрос по очереди.
q1("Petrov").
%q2(table).
%q3;max(A,B).
Пример 15: решить предыдущую задачу с использованием внутренней базы данных. Найденные решения записать в виде фактов внутренней базы данных Пролога. Предусмотреть проверку факта, являющегося ответом на запрос в БД. Если такой факт существует, то выдать его в качестве ответа на запрос. Если такого факта не существует во внутренней базе данных, то запустить запрос на выполнение и записать результат в БД.
domains
list_colours = symbol*
list_products = product*
name_shop,address,chief,name_product,country = symbol
price =real
product = prod (name_product,price,country,list_colours)
facts
max(name_product,price)
% динамические предикаты для второго и третьего запроса
dq1(address)
dq2(name_shop)
predicates
shop (name_shop,address,chief,list_products)
q1(chief)
q2(name_product)
q21(name_product,list_products)
q3
q31(list_products)
clauses
shop("Company1","Debenko_5","Ivanov",[prod(table,3000,"Italy",[white,
red,black]),prod(chair,4000,"Japan",[brown,grey])]).
shop("Company2","S.Lazo_4","Petrov",[prod(sofa,9000,"China",[brown,
black]),prod(chair,5000,"England",[red,grey])]).
shop("Company3","Sadovaya_3","Sidorov",[prod(sofa,19000,"Mexico",
[black,white])]).
shop("Company4","Dachnaya_2","Orlov",[prod(bookcase,7000,"Russia",
[brown,black]),prod(table,6000,"Spain",[red,grey])]).
shop("Company5","Pobeda_1","Galkin",[prod(bed,5000,"China",[brown,
black]),prod(arm_chair,21000,"Japan",[red,grey])]).
% проверяем наличие факта, являющегося ответом на запрос в БД, если такой факт существует, то выдаём его в качестве ответа на запрос, печатаем перед ним "*".
q1(_):-dq1(A), write("*",A),nl.
% Если такого факта не существует во внутренней базе данных, то запускаем запрос на выполнение и записываем результат в БД.
q1(F):-not(dq1(_)), shop (_,A,F,_),write(A),nl,assert(dq1(A)).
q2(_):-dq2(A), write("*",A),nl,fail.
q2(P):-not(dq2(_)), shop(N,_,_,L),q21(P,L),write(N),nl,assert(dq2(N)),fail.
q21(H,[H1|_]):-H1=prod(H,_,_,_).
q21(H,[_|T]):-q21(H,T).
max(a,0).
q3:-shop(_,_,_,L),q31(L),fail.
q31([]).
q31([H1|T]):-H1=prod(H,P,_,_),max(A,B),P>B,retract(max(A,B)),assert(max(H,P)),q31(T).
q31([H1|T]):-H1=prod(_,P,_,_),max(_,B),P<=B,q31(T).
goal
% Запускаем каждый запрос на исполнение два раза - первый раз программа находит ответ на запрос, а второй раз выдает ответ из БД.
q1("Petrov"),q1("Petrov").
%q2(table);q2(table).
%q3;max(A,B).
Пример 16: Решить логическую головоломку. В пяти домах, окрашенных в разные цвета, обитают мужчины разных национальностей. Они держат разных животных, предпочитают разные напитки и курят сигареты разных марок. Известно, что англичанин живет в красном доме; у испанца есть собака; кофе пьют в зеленом доме; украинец пьет чай; зеленый дом – первый по правую руку от дома цвета слоновой кости; курильщик «Уинстона» держит улиток; сигареты «Кул» курят в жёлтом доме; молоко пьют в среднем доме; норвежец живет в крайнем слева доме; мужчина, курящий «Честерфилд», живет в доме, соседнем с домом мужчины, у которого есть лиса; сигареты «Кул» курят в доме, соседнем с домом, где имеется лошадь; мужчина, предпочитающий «Лаки страйк», пьёт апельсиновый сок; японец курит сигареты «Парламент»; норвежец живет в доме рядом с голубым домом, у одного из мужчин есть зебра, один из мужчин пьет воду. Кто в каком доме живет, какое животное держит, что пьёт и курит?
domains
%описание дома - цвет дома, национальность живущего там мужчины, его животное, напиток и марка сигарет.
house=h(colour,nationality,pet,drink,cigarette)
houses=house*
colour,nationality,pet,drink,cigarette=symbol
predicates
colour(house, colour)
nationality(house, nationality)
pet(house, pet)
drink(house, drink)
cigarette(house, cigarette)
first(house,houses)
middle(house,houses)
solve
neighbourhood(house, house,houses)
neighbourhoodright(house, house,houses)
clauses
% в описании дома цвет дома находится на первом месте
colour(h(C,_,_,_,_),C).
% в описании дома национальность живущего там мужчины находится на втором месте
nationality(h(_,N,_,_,_),N).
% в описании дома животное находится на третьем месте
pet(h(_,_,P,_,_),P).
% в описании дома напиток находится на четвертом месте
drink (h(_,_,_,D,_),D).
% в описании дома сигареты находятся на пятом месте
cigarette(h(_,_,_,_,S),S).
%один из домов - крайний слева
first(X,[X,_,_,_,_]).
% один из домов находится в середине
middle(Y,[_,_,Y,_,_]).
% перебор всех возможных соседних домов
neighbourhood(A,B,[A,B,_,_,_]).
neighbourhood(A,B,[B,A,_,_,_]).
neighbourhood(A,B,[_,A,B,_,_]).
neighbourhood(A,B,[_,B,A,_,_]).
neighbourhood(A,B,[_,_,A,B,_]).
neighbourhood(A,B,[_,_,B,A,_]).
neighbourhood(A,B,[_,_,_, A,B]).
neighbourhood(A,B,[_,_,_, B,A]).
% перебор всех возможных соседних домов, из которых дом B по правую руку от дома A
neighbourhoodright (A,B,[A,B,_,_,_]).
neighbourhoodright (A,B,[_,A,B,_,_]).
neighbourhoodright (A,B,[_,_,A,B,_]).
neighbourhoodright (A,B,[_,_,_, A,B]).
% англичанин живет в красном доме
solve:- neighbourhood(H1,_,Houses), nationality(H1,englishman), colour(H1,red),
%; у испанца есть собака
neighbourhood(H2,_,Houses), nationality(H2, spaniard), pet(H2,dog),
% кофе пьют в зеленом доме
neighbourhood(H3,_,Houses), colour(H3,green), drink(H3, coffee),
% украинец пьет чай
neighbourhood(H4,_,Houses), nationality(H4, ukrainian),
drink(H4, tea),
% зеленый дом – первый по правую руку от дома цвета слоновой кости
neighbourhoodright(H5,H6,Houses), colour(H6,green),
colour(H5, ivory),
%курильщик «Уинстона» держит улиток
neighbourhood(H7,_,Houses), cigarette(H7,winston), pet(H7, snail),
% сигареты «Кул» курят в жёлтом доме;
neighbourhood(H8,_,Houses), cigarette(H8,cool), colour(H8, yellow),
% молоко пьют в среднем доме
middle(H9,Houses), drink(H9, milk),
% норвежец живет в крайнем слева доме;
first(H10, Houses), nationality(H10, norwegian),
% мужчина, курящий «Честерфилд», живет в доме, соседнем с домом мужчины, у которого есть лиса
neighbourhood(H11,H12,Houses), cigarette(H11,chesterfild),pet(H12,fox),
%; сигареты «Кул» курят в доме, соседнем с домом, где имеется лошадь
neighbourhood(H13,H14,Houses), cigarette(H13,cool),pet(H14,horse),
% мужчина, предпочитающий «Лаки страйк», пьёт апельсиновый сок
neighbourhood(H15,_,Houses),cigarette(H15,lakestrike), drink(H15,orange),
% японец курит сигареты «Парламент»
neighbourhood(H16,_,Houses),nationality(H16,japanese), cigarette(H16,parlament),
% норвежец живет в доме рядом с голубым домом
neighbourhood(H17,H18,Houses),nationality(H17,norwegian), colour(H18,blue),
% у одного из мужчин есть зебра
neighbourhood(H19,_,Houses), pet(H19,zebra),
% один из мужчин пьет воду
neighbourhood(H20,_,Houses), drink(H20,water),
write(Houses).
goal
solve.