Пролог-программу можно рассматривать как базу данных: описание отношений частично присутствует в ней в явном виде (факты), а частично - в неявном (правила). По последней причине ее можно также назвать базой знаний. В процессе выполнения программы можно создавать дополнительные предложения языка Пролог, которые включаются в базу. Можно также удалять из базы имеющиеся в ней предложения. Основные предикаты всегда завершаются успешно, а в качестве своего побочного эффекта вызывают:
consult(F) - чтение предложений пролог-программы из файла F;
reconsult(F) – аналогично consult(F), но в отличие от последнего - переопределяет ранее введенные определения;
assert(С) - добавление к базе данных предложения С;
retract( С) - удаление предложения, сопоставимого с С.
При возврате добавленные предложения из базы не удаляется, удаленные - не возвращается.
При добавлении нового предложения может оказаться важным указать, на какое место в базе данных его следует поместить. Такую возможность обеспечивают предикаты:
asserta(С) - помещает С в начале базы данных;
assertz( С) - помещает С в конец базы данных.
В большинстве реализаций база данных делится на статическую и динамическую. Детали работы встроенных предикатов зависят от конкретной реализации Пролога.
Пример 3.11.1. Таблица умножения.
Описание программы:
таблица_умножения(L):- принадлежит(X, L), принадлежит(Y, L), Z is X*Y, assert(произв(X,Y,Z)), fail.
таблица_умножения(L).
Вопросы к системе.
?- произв(А, В, 8).
No
?- таблица_умножения([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]).
Yes
?- произв(А, В, 8).
А = 1, В = 8;
А = 2, В = 4;
А = 4, В = 2;
А = 8, В = 1;
Пример 3.11.2. Вычисление наибольшего общего делителя нескольких чисел.
Исходные числа находятся в базе данных в виде фактов вида «число(X)»/
Описание программы:
нод(X1):-число(X), число(Y), X>Y, Z is X-Y, retract(число(X)), един(Z), нод(X1),!.
нод(X):-число(X).
един(X):- число(X),retract(число(X)), един(X).
един(X):-assertz(число(X)).
Вопросы к системе.
?- assert(число(10)).
Yes
?- assert(число(15)).
Yes
?- assert(число(25)).
Yes
?- assert(число(30)).
Yes
?- нод(X).
X=5
По окончании работы база данных будет содержать единственное предложение вида число(5). Предикат един(X) обеспечивает единственность вхождения добавляемой записи в базу данных. Можно вместо един(X) использовать assertz(число(X)), но в этом случае по окончании работы база данных будет содержать несколько предложений вида число(5).
Пример 3.11.3.Исключение повторов в базе данных.
Описание программы:
in(a,b).
in(a,b).
in(c,b).
in(b,a).
in(c,b).
find(X,Y):-in1(X,Y),retract(in1(X,Y)),find(X,Y),!.
find(X,Y):-assertz(in1(X,Y)).
fiall:-in(X,Y),find(X,Y),fail.
fiall.
Вопросы к системе.
?- in(X,Y).
X= a, Y= b;
X= a, Y= b;
X= c, Y= b;
X= b, Y= a;
X= c, Y= b;
?- in1(X,Y).
No
?- fiall
Yes
?- in(X,Y)
X= a, Y= b;
X= a, Y= b;
X= c, Y= b;
X= b, Y= a;
X= c, Y= b;
?- in1(X,Y)
X= a, Y= b;
X= c, Y= b;
X= b, Y= a;
3.12. Предикаты поиска
bagof(X, P, L) - порождает список L всех объектов X, удовлетворяющих предикату Р.
Пример 3.12.1., Разбиения букв на два класса - гласные и согласные.
В базе данных содержатся предложения:
класс(а, глас).
класс(b, согл).
класс(с, согл).
класс(d, согл).
класс(е, глас).
класс(f, согл).
Вопросы к системе.
?- bagof(Буква, класс(Буква, согл), Буквы).
Буквы = [b, c, d, f]
?- bagof(Буква, класс(Буква, Класс), Буквы).
Класс = глас, Буквы = [а,е];
Класс = согл, Буквы = [b, c, d, f]
Если bagof(X, Р, L) не находит ни одного решения для Р, то цель bagof терпит неудачу. Если один и тот же Х найден многократно, то все его экземпляры будут занесены в L.
setof(X, P, L) - порождает список L объектов X, удовлетворяющих Р, но список L будет упорядочен, а из всех повторяющихся элементов, если таковые есть, в него попадет только один.
findall(X, P, L) - порождает список объектов, удовлетворяющих Р. В отличии от bagof собирает в список все объекты X, с различными значениями переменных из P, не входящих в X.
Пример 3.12.1 (продолжение)
Вопросы к системе.
?- setof(Класс/Буква, класс(Буква, Класс), Список).
Список = [глас/а, глас/е, согл/b, согл/с, согл/d, согл/f]
?- findall(Буква, класс( Буква, Класс), Буквы).
Буквы= [a, b, c, d, e, f]
Если не существует ни одного объекта X, удовлетворяющего P, то findall выдает L = [].
Пример 3.12.2.Вариант программирования предиката findall
findall(X, Цель, ХСпис):- саll(Цель), assert(очередь(X)), fail;
findall(X, Цель, ХСпис):- assertz(очередь(дно)), собрать( ХСпис).
собрать(L):- retract(очередь(Х)), !, собрать1(Х ,L).
собрать1(дно ,[]):-!.
собрать1(X , [X | Остальные]):- собрать(Остальные).
Упражнения 3.9.2.Исследовать работу программы, исключающей повторы в базе данных (пример 3.11.3).
1. После ввода программы ввести вопросы:
?- in(X,Y)
?- in1(X,Y)
?- fiall
?- in(X,Y)
?- in1(X,Y)
2. Исследовать варианты:
· без отсечения в предикате find;
· заменить в предикате find assertz на assert и asserta.
3. Сравнить работу программы с работой предиката findall.
Для этого ввести вопрос: findall(X,in(X,Y),L)
3.13. Решение головоломки на языке ПРОЛОГ(задача Эйнштейна)
Рассмотрим головоломку Эйнштейна,
Условия задачи.
Общие условия
1. Есть 5 домов, каждый разного цвета, и пронумерованы они слева направо.
2. В каждом доме живет по одному человеку отличной друг от друга национальности.
3. Каждый жилец пьет только один определенный напиток, курит определенную марку табака и держит определенное животное.
4. Никто из 5 человек не пьет одинаковые с другими напитки, не курит одинаковый табак и не держит одинаковое животное.
Дополнительные условия:
1. Англичанин живет в красном доме.
2. Швед держит собаку.
3. Датчанин пьет чай.
4. Зеленый дом стоит слева от белого.
5. Жилец зеленого дома пьет кофе.
6. Человек, который курит Pall Mall, держит птицу.
7. Жилец из среднего дома пьет молоко.
8. Жилец из желтого дома курит Dunhill.
9. Норвежец живет в первом доме.
10. Курильщик Marlboro живет около того, кто держит кошку.
11. Человек, который содержит лошадь, живет около того, кто курит Dunhill.
12. Курильщик Winfield пьет пиво.
13. Норвежец живет около голубого дома.
14. Немец курит Rothmans.
15. Курильщик Marlboro живет по соседству с человеком, который пьет воду.
Вопрос: кому принадлежит рыба?
Решение задачи
Общие условия находят свое отражение в пролог-программе в виде специального списка из пяти структур (соответствующих пяти домам), каждая из которых содержит пять полей, соответствующих цвету дома, национальности жильца, напитку, марке табака и животному.
list([f_(C1,N1,D1,K1,A1), f_(C2,N2,D2,K2,A2),
f_(C3,N3,D3,K3,A3), f_(C4,N4,D4,K4,A4),
f_(C5,N5,D5,K5,A5)]).
Для упрощения работы с полями структуры служат следующие предикаты:
color(f_(A,B,C,D,E),A).
nationality(f_(A,B,C,D,E),B).
drink(f_(A,B,C,D,E),C).
smok(f_(A,B,C,D,E),D).
animal(f_(A,B,C,D,E),E).
Пространственные отношения между домами программируются в виде следующих предикатов:
Быть слева (считаем, что слева – значит слева рядом).
left(A,B,[A,B,C,D,E]).
left(B,C,[A,B,C,D,E]).
left(C,D,[A,B,C,D,E]).
left(D,E,[A,B,C,D,E]).
Быть в центре.
center(C,[A,B,C,D,E]).
Быть первыи.
first(A,[A,B,C,D,E]).
Быть соседом.
near(X,Y,Z):-near1(X,Y,Z).
near(X,Y,Z):-near1(Y,X,Z).
near1(A,B,[A,B,C,D,E]).
near1(B,C,[A,B,C,D,E]).
near1(C,D,[A,B,C,D,E]).
near1(D,E,[A,B,C,D,E]).
Дополнительные условия программируются следующим предложением (используем встроенный предикат member):
cond(F):- list(F), %заголовок предиката и сопоставление переменной с основной структурой
% Англичанин живет в красном доме
member(M11,F),
nationality(M11, england),
color(M11,red),
% Швед держит собаку.
member(M12,F),
nationality(M12, sweden),
animal(M12,dog),
% Датчанин пьет чай.
member(M13,F),
nationality(M13, danmark),
drink(M13,tea),
% Зеленый дом стоит слева от белого.
left(M14,M24,F),
color(M14,green),
color(M24,white),
% Жилец зеленого дома пьет кофе.
member(M15,F),
color(M15,green),
drink(M15,cafe),
% Человек, который курит Pall Mall, держит птицу.
member(M16,F),
smork(M16,pallmall),
animal(M16,bird),
% Жилец из среднего дома пьет молоко.
middle(M17,F),
drink(M17,milk),
% Жилец из желтого дома курит Dunhill.
member(M18,F),
color(M18,yellow),
smork(M18,danhill),
% Норвежец живет в первом доме.
first1(M19,F),
nationality(M19, norway),
% Курильщик Marlboro живет около того, кто держит кошку.
near(M110,M210,F),
smork(M110,marlboro),
animal(M210,cat),
% Человек, который содержит лошадь, живет около того, кто курит Dunhill.
near(M111,M211,F),
smork(M211,danhill),
animal(M111,horse),
% Курильщик Winfield пьет пиво.
member(M112,F),
smork(M112,winfield),
drink(M112,beer),
% Норвежец живет около голубого дома.
near(M113,M213,F),
nationality(M113, norway),
color(M213,blue),
% Немец курит Rothmans.
member(M114,F),
nationality(M114, german),
smork(M114,rothmans),
% Курильщик Marlboro живет по соседству с человеком, который пьет воду.
near(M115,M215,F),
smork(M115,marlboro),
drink(M215,water).
Вопрос записывается в виде следующего предложения. Определим цвет дома и национальность владельца рыбы.
% кому принадлежит рыба?
queries(F,[['Fish -', C, N]]):-member(Q1,F),
nationality(Q1,N),
color(Q1,C),
animal(Q1,fish).
Наконец основной предикат можно определить следующим образом.
main(X,Z):- cond(X), queries(X,Z).
После запроса к системе получим ответ.
?- main(X,Z).
X = [f_(yellow, norway, water, danhill, cat), f_(blue, danmark, tea, marlboro, horse), f_(red, england, milk, pallmall, bird), f_(green, german, cafe, rothmans, fish), f_(white, sweden, beer, winfield, dog)]
Y = [['Fish -', green, german]]
Переменная X содержит всю структуру, а Y –ответ на поставленный вопрос.
Можно несколько ослабить условие задачи. Например, отношение «быть слева» можно интерпретировать в смысле слева и необязательно рядом. Это приведет к небольшим изменениям в программе (в предикате left) и по запросу будет выдано несколько вариантов решений.
Дата: 2016-10-02, просмотров: 234.