Лабы_ЭкспСист / Лабораторная №3
.docЛабораторная работа №3.
Предикаты.
Цель работы: Получить представление о предикатах Visual Prolog.
Задание: Реализовать две программы по рисованию карты.
Порядок выполнения:
3.1.Получите начальные сведения о предикатах Visual Prolog.
3.2.Создайте проект mapDataBase. Реализуйте программу находящую единственное решение.
3.3. Создайте проект drawMap. Реализуйте программу находящую множественные решения.
3.1. Предикаты
Предикаты это функции, чьим образом является множество {true, false}. Есть несколько предикатов, известных любому, кто приложил руку к программированию. Вот они:
X>Y возвращает true если X больше, чем Y, иначе возвращает false.
X<Y возвращает true если X меньше, чем Y, иначе возвращает false.
X=Y возвращает true если X равен Y, иначе возвращает false.
Предикат с одним аргументом говорит о свойстве его аргумента. Примеры одноместных предикатов:
positive(X): true если X положительный, false в любом другом случае.
exists(“text.txt”): true если файл text.txt существует, иначе false.
Предикат более чем с одним аргументом показывает, что между его аргументами существует отношение. В случае X=Y это отношение – равенство.
Еще примеры предикатов:
positive(X)
true если X положителен, иначе false
rain(Temperature, Pressure, Humidity)
true, если будет дождь при заданных температуре, давлении и влажности. Например,
rain(100, 1.2, 90)
вернет true, если пойдет дождь, когда ваши измерительные приборы покажут 100°F, 1.2 атмосфер, и 90% относительной влажности.
invest(Rate, StandardDeviation, Risk)
По заданным Rate, StandardDeviation, и приемлемом Risk, этот предикат возвращает true, если вам стоит выбрать инвестирование.
3.2. Решения
Предположим, что у вас есть предикат city(Name, Point), который определяет координаты города на карте. Предикат city/2 имеет домен (доменом называется множество возможных значений аргумента)
city : (string Name, pnt Position).
и может быть определен как база данных фактов:
city(“Salt Lake”, pnt(30, 40)).
city(“Logan”, pnt(100, 120)).
city(“Provo”, pnt(100, 200)).
city(“Yellowstone”, pnt(200, 100)).
Этот предикат проверяет, является ли заданное положение заданного города верным, когда кто-либо не уверен насчет этого. Вот несколько запросов, которые можно задать предикату city/2.
city("Salt Lake", pnt(30, 40)) true
city("Logan", pnt(100, 200)) false
city("Provo", pnt(100, 200)) true
Предикат, возвращающий координаты города по заданному названию, может оказаться намного более полезным.
city(“Salt Lake”, P) P=pnt(30, 40).
В этом новом виде предикатов, символы, начинающиеся с заглавной буквы, называются переменными. Примеры переменных: X, Y, Temperature, Rate.
Когда вы используете переменную, как P в запросе city(“Salt Lake”, P), вы желаете знать, что нужно подставить вместо P, чтобы сделать предикат city(“Salt Lake”, P) true, то есть истинным. Ответом является P=pnt(30, 40). Таким образом, давайте определим предикат city/2.
-
Создайте новый проект с именем mapDataBase.
-
Добавьте новый пакет к корневому каталогу дерева проекта: mapDataBase / plotter.
-
Создайте новую форму: plotter /map. Добавьте следующие кнопки к новой форме: logan_ctl, saltLake_ctl, provo_ctl.
-
Window Edit. Измените размеры новой формы. Окно формы должно иметь достаточный размер, чтобы отобразить нашу «карту». Оставьте больше пустого места в центре формы.
-
Включите пункт Project Tree/TaskMenu File/New.
-
Project Tree/TaskWindow.win/Code Expert. Добавьте
clauses
onFileNew(S, _MenuTag) :-
X=map::new(S), X:show().
к Menu/TaskMenu/id_file/id_file_new/onFileNew.
-
Создайте класс draw. Чтобы создать новый класс и вложить его в пакет plotter, выберите папку plotter в дереве проекта и выберите пункт File/New из панели задач VDE. Название класса draw, и галочка Create Objects снята. Откомпилируйте проект, для того, чтобы внести прототип нового класса в дерево проекта. Затем отредактируйте draw.cl и draw.pro как показано ниже (лист.1,2).
-
Для того, чтобы вызывать предикат drawThem кнопками городов, двойным нажатием на кнопке logan_ctl и отредактируйте фрагмент кода обработчика события нажатия кнопки.
clauses
onLoganClick(S) =button::defaultAction() :-
Parent=S:getParent(),
P=Parent:getVPIWindow(),
draw::drawThem(P, “Logan”).
Повторите действия для “Salt Lake” и “Provo”. Не забудьте заменить названия предложений на onSaltLakeClick (S) и onProvoClick (S) соответственно, а также названия городов в drawThem. Откомпилируйте проект и запустите программу. В новом приложении, выберите пункт File/New. Появится новая форма. Когда вы нажимаете на кнопку, программа нарисует соответствующий город.
Листинг 1.
% File: draw.cl
class draw
open core, vpiDomains
predicates
classInfo : core::classInfo.
drawThem:(windowHandle, string) procedure.
end class draw
Листинг 2.
% File:draw.pro
implement draw
open core, vpiDomains, vpi
constants
className = "plotter/draw".
classVersion = "".
class facts
city:(string, pnt).
clauses
classInfo(className, classVersion).
city("Salt Lake", pnt(30, 40)).
city("Logan", pnt(100, 120)).
city("Provo", pnt(100, 80)).
city("Yellowstone", pnt(200, 100)).
drawThem(Win, Name) :-
B= brush(pat_solid, color_red),
winSetBrush(Win, B),
city(Name, P), !, P= pnt(X1, Y1),
X2= X1+20, Y2= Y1+20,
drawEllipse(Win, rct(X1, Y1, X2, Y2)).
drawThem(_Win, _Name).
end implement draw
3.3. Множественные решения
В предыдущем разделе вы видели предикаты, которые использовали свои переменные для получения решения, а не для проверки истинно отношение или ложно. В примере, предикат city/2 использован для получения только одного решения. Тем не менее, существуют ситуации, требующие более одного решения. Пусть conn/2 будет предикатом, устанавливающим связь между двумя городами.
conn(pnt(30, 40), pnt(100, 120)).
conn(pnt(100, 120), pnt(100, 200)).
conn(pnt(30, 40), pnt(200, 100)).
.
.
.
Вы можете использовать его для получения всех соединений между городами, как показано в примере:
conn(pnt(30, 40), W). W=pnt(100, 120)
W=pnt(200, 100)
conn(X, Y). X=pnt(30, 40) / Y=pnt(100, 120)
X=pnt(100, 120) / Y=pnt(100, 200)
X=pnt(30, 40) / Y=pnt(200, 100)
Рассмотрим запрос:
conn(pnt(30, 40), W)?
Ответом может быть как W=pnt(100, 120), так и W=pnt(200, 100).
3.4. Программа, использующая предикаты со множественными решениями
Давайте создадим программу, чтобы показать всю прелесть возможности множественных решений в Прологе – возможности, отсутствующей в других языках.
-
Project Settings. Создайте новый проект с именем drawMap.
-
Create Project Item: Package. Добавьте новый пакет к корневому каталогу дерева проекта: drawMap / plotter.
-
Create Project Item: Window. Создайте новую форму: plotter /map.
-
Form Edit. Увеличьте размеры новой формы для карты.
-
Project Tree/TaskMenu. Включите пункт File/New.
-
Project Tree/TaskWindow.win/Code Expert. Добавьте
clauses
onFileNew(S, _MenuTag) :-
F=map::new(S), F:show().
к Menu/TaskMenu/id_file/id_file_new/onFileNew.
-
Создайте класс draw. Откомпилируйте проект, затем отредактируйте draw.cl и draw.pro как показано ниже (лист.3,4).
-
Project Tree/map.frm/Properties/Events. PaintResponder→onPaint:
clauses
onPaint(S, _Rectangle, _GDIObject) :-
W=S:getVPIWindow(),
draw::drawThem(W).
Листинг 3.
% File:draw.pro
implement draw open core, vpiDomains, vpi constants className = "plotter/draw". classVersion = "". class facts city:(string Name, pnt Position). conn:(pnt, pnt). class predicates connections:( windowHandle). drawCities:(windowHandle). clauses classInfo(className, classVersion). city("Salt Lake", pnt(30, 40)). city("Logan", pnt(100, 120)). city("Provo", pnt(100, 160)). city("Yellowstone", pnt(200, 100)). conn(pnt(30, 40) , pnt(100, 120)). conn(pnt(100, 120), pnt(100, 160)). conn(pnt(30, 40), pnt(200, 100)). drawCities(W) :- city(N, P), P= pnt(X1, Y1), X2= X1+10, Y2= Y1+10, drawEllipse(W, rct(X1, Y1, X2, Y2)), drawText(W, X1, Y1, N), fail. drawCities(_Win). connections(Win) :- conn(P1, P2), drawLine(Win, P1, P2), fail. connections(_Win). drawThem(Win) :- connections(Win), drawCities(Win). end implement draw
Листинг 4.
% File:draw.cl
class draw open core, vpiDomains predicates classInfo : core::classInfo. drawThem:(windowHandle) procedure. end class draw
Если вы откомпилируете программу, вы должны получить окно с картой на нём, наподобие рис.3.1., когда нажмёте File/New.
Рис.3.1. Карта шт. Юта.