Мова програмування Пролог: переваги та недоліки логічного програмування
I Вступ
На сьогоднішній день існує багато мов програмування, та їх варіантів, які використовуються як починаючими програмістами, так і професіоналами. Але більшість з них не може надати простого рішення при розв'язанні навіть не дуже складної задачі про родинний зв'язок. Прологовський програміст надає простий та логічний опис поняття "дідусь": дідусь - батько батька. Мовою Пролога це буде виглядати так:
grandfather(X, Z):-father(X, Y),parent(Y, Z).
Тільки-но Пролог-система дізналася, що таке дідусь, до неї можна звернутися з питанням, наприклад: хто є дідусем Івана? У визначеннях Пролога це питання та типова відповідь на нього мають вигляд:
grandfather(X, ivan)
X=petro;
X=egor.
Яким чином вирішувати цю задачу, як перебирати базу даних, в якій записані усі відношення "батько-син", це вже проблема самої Пролог-системи. Програміст тільки повідомляє системі те, що йому відомо та задає питання. Його в більшій ступені цікавлять знання і в меншій - алгоритми, за допомогою яких з цих знань вилучається необхідна інформація. Саме цьому для програмування мовою Пролог необхідно свіже логічне мислення, при якому знання таких мов програмування як Паскаль або Бейсик може бути справжньою поміхою. До речі, назва мови ПРОЛОГ є скороченням "ПРОграмування мовою ЛОГіки"
I.1 Актуальність роботи
Створення штучного інтелекту було і є актуальним протягом багатьох років. Перша версія мови програмування Пролог була створена ще в 1983 році і вдосконалюється до сьогодення. Останньою версією є Visual Prolog для Windows, який, на жаль, мені не довелось отримати з причин його не дуже широкого розповсюдження в нашій країні. Чому саме в нашій країні? Тому що за кордоном, наприклад, в Сполучених Штатах Америки, Пролог викладають у багатьох вузах. Кожен рік там проводяться конференції з проблем штучного інтелекту, які у більшості присвячені експертним системам та нейромережам. Саме для створення експертних систем Пролог підходить якнайкраще.
I.2 Мета і задачі дослідження
Мета моєї роботи - пізнати мову програмування Пролог та її можливості та порівняти їх з можливостями інших мов програмування; поширити свої знання у розумінні логічних мов програмування. Моєю задачею було створення не дуже складної програми мовою Прологу та Паскалю і їх порівняння.
I.3 Практичне значення
Можна використовувати матеріал моєї роботи в якості простого прикладу, який демонструє приоритетні можливості мови Пролог.
I.4 Особистий внесок
Моїм особистим внеском є аналіз отриманих мною знань про мову програмування Пролог та виділення найголовнішого. Крім цього мною були розроблені дві програми, що демонструють різницю між описуючими та процедурно-орієнтованими мовами програмування.
II Основна частина
II.1 З історії створення мови Пролог
Ідея використання логіки у мовах програмування виникла у початку 70-х років. Першими дослідниками, які розроблювали цю ідею, були Роберт Ковальський, Маартен ван Емден та Ален Колмерое з Единбургу. Своєю популярністю серед професіоналів створення штучного інтелекту Пролог зобов'язаний ефективною реалізацією цієї мови в Единбурзі Девідом Уорреном.
Існує безліч історично складених та протидіючих один одному поглядів на Пролог. Пролог швидко завоював популярність в Європі як практичний інструмент програмування. В Японії Пролог опинився у центрі розробки комп'ютерів нового покоління. З іншого боку, через визначені історичні факти, в США Пролог отримав визнання трохи пізніше. Один з цих факторів був пов'язаний з Мікропленнером, мовою, близькою до логічного програмування, але реалізованою неефективно [1, с.15]. Цей негативний досвід, який відноситься до Мікропленнера, був невиправдано розповсюджений і на Пролог. Але пізніше після появи ефективної реалізації, запропонованої Девідом Уорреном, цей погляд було скасовано.
II.2 Принцип роботи
Своїм корінням Пролог уходить в математичну логіку. Якщо традиційні мови програмування є процедурно-орієнтованими, Пролог заснований на декларативній точці зору на програмування. Ця якість Пролога змінює програмістське мислення та робить програмування мовою Пролога захоплюючим зайняттям, що потребує інтелектуальних зусиль.
Мова програмування Пролог базується на обмеженому наборі механізмів, що включають до себе зіставлення зразків, деревовидне представлення структур даних та автоматичне повернення. Цей невеликий набір створює дивовижно потужний та гнучкий програмний апарат. Пролог особливо добре застосовувати для вирішення задач, в яких фігурують об'єкти (зокрема структури) та відносини між ними. При використанні предикат можна вказувати як точні дані, так і відносини між ними.
Пролог - це мова програмування, призначена для обробки символьної нечислової інформації. На малюнку представлено простий приклад - родинні відносини. Той факт, що Том є батьком Боба можна представити так:
parent(tom, bob).
parent(pam,bob).
parent(tom,bom).
parent(tom,liz).
parent(bob,ann).
parent(bob,pat).
parent(pat,jim).
Ця програма містить шість речень. Кожне речення оголошує один факт існування відношення "батько". Питання до системи - це завжди послідовність, що складається з однієї або кількох цілей. Для того, щоб відповісти на питання, система намагається досягти всіх вказаних цілей. Що означає досягти цілі? Досягти цілі - це означає показати, що твердження, які містяться в питанні, дійсні у реченні, що усі відносини програми дійсні. Іншими словами, досягти цілі - це означає показати, що вона логічно витікає з фактів та правил програми. Якщо питання містить змінні, система повинна до того ж знайти конкретні об'єкти, які забезпечують досягнення цілі.
II.3 Можливості удосконалення
В майбутньому я планую почати вивчення Visual Prolog, тому що саме при використанні сучасного програмного забезпечення можна створити продукт, який буде максимально використовувати можливості нового обладнання.
II.4 Контрольні приклади питань
II.4.1 Приклад використання предикати concat (конкатенація - об'єднання двох строк)
Goal: concat("aaa","bbb",X)
X=aaabbb
1 Solution
Goal: concat("aaa","bbb","aaabbb")
Yes
Goal: concat("aaa","bbb","aaa----bbb")
No
Goal: concat(X,"bbb","aaa----bbb")
X=aaa----
1 Solution
Goal: concat("aaa",X,"aaa----bbb")
X=----bbb
1 Solution
II.4.2 Приклад використання предикати frontchar (перший символ)
Goal: frontchar("TPROLOG",CH,REST)
CH=T, REST=PROLOG
1 Solution
Goal: frontchar("TPROLOG",'T',REST)
REST=PROLOG
1 Solution
Goal: frontchar("TPROLOG",'P',"ROLOG")
No
Goal: frontchar(X,'T',"PROLOG")
X=TPROLOG
1 Solution
II.4.3 Приклад використання предикати random (випадкове число)
Goal: random(X)
X=0.438218271
1 Solution
Goal: random(X)
X=0.36520984623
1 Solution
III Висновки
Навіть людина, далека від програмування, визначить, що програма, написана мовою Пролог (Relation.pro) значно простіша за програму, написану мовою Паскаль (Relation.pas) . Усе це є наслідком спрощення логічного програмування у мові Пролог. Але програміст, який вже давно знайомий з мовою Паскаль, спочатку не зможе розуміти текст програми, написаної мовою Пролог. Саме цьому при вивченні Прологу не рекомендується знання інших мов програмування (за винятком ЛІСПа - він також є логічною мовою програмування). Та на жаль, Пролог є ефективнішим при вирішенні задач не всіх типів. Простим прикладом є комп'ютерні ігри, наприклад, Worms 3D - сама реалізація якого зроблена мовою Сі, а програмування інтелекту комп'ютерних опонентів зроблено мовою Lua [2] - поки що не дуже розповсюдженою мовою логічного програмування. З цього можна зробити висновок, що найбільш ефективним є поєднання логічних та процедурно-орієнтованих мов програмування.
Список використаної літератури:
I. Bratko: "Prolog Programming for Artificial Intelligence", Addison-Wesley Publishing Company, Inc., 1990 (пер. с англ.);
Журнал Комп'ютери + Програми №1-2004 (Електронна версія);
Інтернет - ресурси (пошук за допомогою Google: google.com.ua);
Стандартний довідник по Прологу (prolog.hlp).
Лістинг програм
Файл "Relation.pro"
predicates
parent(symbol,symbol)
father(symbol,symbol)
mother(symbol,symbol)
son(symbol,symbol)
daughter(symbol,symbol)
grandson(symbol,symbol)
granddaughter(symbol,symbol)
male(symbol)
female(symbol)
offspring(symbol,symbol)
grandparent(symbol,symbol)
grandmother(symbol,symbol)
grandfather(symbol,symbol)
sister(symbol,symbol)
brother(symbol,symbol)
forefather(symbol,symbol)
clauses
parent(pam,bob).
parent(tom,bob).
parent(tom,liz).
parent(bob,pat).
parent(bob,ann).
parent(pat,jim).
female(pam).
female(liz).
female(ann).
female(pat).
male(jim).
male(tom).
male(bob).
offspring(Y,X):-
parent(X,Y).
mother(X,Y):-
parent(X,Y),
female(X).
father(X,Y):-
parent(X,Y),
male(X).
grandparent(X,Z):-
parent(X,Y),
parent(Y,Z).
grandmother(X,Y):-
grandparent(X,Y),
female(X).
grandfather(X,Y):-
grandparent(X,Y),
male(X).
sister(X,Y):-
parent(Z,X),
parent(Z,Y),
female(X),
not(X=Y).
brother(X,Y):-
parent(Z,X),
parent(Z,Y),
male(X),
not(X=Y).
son(X,Y):-
parent(Y,X),
male(X).
daughter(X,Y):-
parent(Y,X),
female(X).
grandson(X,Y):-
grandparent(Y,X),
male(X).
granddaughter(X,Y):-
grandparent(Y,X),
female(X).
forefather(X,Z):-
parent(X,Z).
forefather(X,Z):-
parent(X,Y),
forefather(Y,Z).
Файл "Relation.pas"
uses crt;
const
maxparent=6;
var
parent, offspring, father, mother, son, daughter: array [1..maxparent,1..2] of byte;
grandparent, grandfather, grandmother, grandson, granddaughter, sister, brother: array [1..maxparent,1..2] of byte;
forefather: array[1..60,1..2] of byte;
male: array [1..7] of boolean;
name: array [1..7] of string;
index, indexx: byte;
maxfather, maxgrand, maxmother, maxoffspring, maxson, maxdaughter, maxsister, maxbrother: byte;
maxgrandfather, maxgrandmother, maxgrandson, maxgranddaughter, maxforefather: byte;
st, nd: string;
begin
name[1]:='pam'; male[1]:=false;
name[2]:='bob'; male[2]:=true;
name[3]:='tom'; male[3]:=true;
name[4]:='liz'; male[4]:=false;
name[5]:='ann'; male[5]:=false;
name[6]:='pat'; male[6]:=false;
name[7]:='jim'; male[7]:=true;
parent[1,1]:=1; parent[1,2]:=2;
parent[2,1]:=3; parent[2,2]:=2;
parent[3,1]:=3; parent[3,2]:=4;
parent[4,1]:=2; parent[4,2]:=5;
parent[5,1]:=2; parent[5,2]:=6;
parent[6,1]:=6; parent[6,2]:=7;
maxgrand:=0;
maxfather:=0;
maxmother:=0;
maxsister:=0;
maxbrother:=0;
maxgrandfather:=0;
maxgranddaughter:=0;
maxgrandson:=0;
maxgranddaughter:=0;
maxoffspring:=maxparent;
maxforefather:=maxparent;
for index:=1 to maxparent do begin
forefather[index,1]:=parent[index,1];
forefather[index,2]:=parent[index,2];
offspring[index,1]:=parent[index,2];
offspring[index,2]:=parent[index,1];
if male[parent[index,1]] then begin
maxfather:=maxfather+1;
father[maxfather,1]:=parent[index,1];
father[maxfather,2]:=parent[index,2];
end else begin
maxmother:=maxmother+1;
mother[maxmother,1]:=parent[index,1];
mother[maxmother,2]:=parent[index,2];
end;
if male[parent[index,2]] then begin
maxson:=maxson+1;
son[maxson,1]:=parent[index,2];
son[maxson,2]:=parent[index,1];
end else begin
maxdaughter:=maxdaughter+1;
daughter[maxdaughter,1]:=parent[index,2];
daughter[maxdaughter,2]:=parent[index,1];
end;
for indexx:=1 to maxparent do
if parent[index,1]=parent[indexx,2] then begin
maxgrand:=maxgrand+1;
maxforefather:=maxforefather+1;
forefather[maxforefather,1]:=parent[indexx,1];
forefather[maxforefather,2]:=parent[index,2];
grandparent[maxgrand,1]:=parent[indexx,1];
grandparent[maxgrand,2]:=parent[index,2];
end;
end;
for index:=1 to maxdaughter do
for indexx:=1 to maxoffspring do
if (daughter[index,2]=offspring[indexx,2]) and
(daughter[index,1]<>offspring[indexx,1]) then
begin
maxsister:=maxsister+1;
sister[maxsister,1]:=daughter[index,1];
sister[maxsister,2]:=offspring[indexx,1];
end;
for index:=1 to maxson do
for indexx:=1 to maxoffspring do
if (son[index,2]=offspring[indexx,2]) and
(son[index,1]<>offspring[indexx,1]) then begin
maxbrother:=maxbrother+1;
brother[maxbrother,1]:=daughter[index,1];
brother[maxbrother,2]:=offspring[indexx,1];
end;
for index:=1 to maxgrand do begin
if male[grandparent[index,2]] then begin
maxgrandson:=maxgrandson+1;
grandson[maxgrandson,1]:=grandparent[index,2];
grandson[maxgrandson,2]:=grandparent[index,1];
end else begin
maxgranddaughter:=maxgranddaughter+1;
granddaughter[maxgranddaughter,1]:= grandparent[index,2];
granddaughter[maxgranddaughter,2]:= grandparent[index,1];
end;
if male[grandparent[index,1]] then begin
maxgrandfather:=maxgrandfather+1;
grandfather[maxgrandfather,1]:= grandparent[index,1];
grandfather[maxgrandfather,2]:= grandparent[index,2];
end else begin
maxgrandmother:=maxgrandmother+1;
grandmother[maxgrandmother,1]:= grandparent[index,1];
grandmother[maxgrandmother,2]:= grandparent[index,2];
end;
end;
for index:=1 to maxgrand do
for indexx:=1 to maxparent do begin
if parent[indexx,2]=grandparent[index,1] then begin
maxforefather:=maxforefather+1;
forefather[maxforefather,1]:=parent[indexx,1];
forefather[maxforefather,2]:= grandparent[index,2];
end;
end;
clrscr;
for index:=1 to 7 do if name[index]='jim' then
indexx:=index;
for index:=1 to maxforefather do
if forefather[index,2]=indexx then
writeln(name[forefather[index,1]]);
repeat until keypressed;
readkey;
clrscr;
for index:=1 to maxforefather do
writeln(name[forefather[index,1]], ' ', name[forefather[index,2]]);
repeat until keypressed;
end.