Пример:
ценно (злато).
харесва (джон, мери).
жена (мери).
Синтактични особености:
- фактът винаги завършва с точка,
- префиксен запис на отношенията,
- имената на всички обекти и отношения започват
с малка буква,
- броят на аргументите в отношенията, както
и редът им, е съществен - две отношения с еднакви имена, но с различен
брой аргументи, се считат за различни.
Отношенията ще наричаме предикати, а аргументите им обекти. Интерпретацията им зависи от пишещия програмата, за Пролог това са само синтактични обекти.
2. Въпроси (Цели). След като имаме въведени няколко факта, ние можем да искаме да попитаме Пролог дали е вярно нещо. За целта ние задаваме въпрос, който изглежда така:
?- жена (мери).
С което искаме да попитаме дали от съвкупността от факти,
които сме написали, следва, че Мери е жена. Пролог започва търсене отгоре
надолу, докато получи или не, пълно съвпадение с въпроса. Ако има такова,
отговаря с "yes", а иначе с "no". Отговорът "no" означава, че Пролог не
може да
изведе от съвкупността от факти, която ще наричаме база
от знания, дадения в целта предикат. Например отговорът на горния въпрос
е "yes", но отговорът на въпроса
?- жена (джейн).
е "no", което не означава че Джейн не е жена.
Синтактични особености:
-целта започва с ?- и завършва с точка.
На нас може да ни се иска да зададем въпрос: "Има ли информация в нашата база от знания дали съществуват жени?". Ние естествено можем да вземем всички женски имена, които са краен брой и за всяко едно от тях да питаме, но това е твърде умопомрачително, но можем да питаме:
?- жена (X).
3. Променливи.
Синтактични особености:
- променливите започват с главна буква или със
символа за подчертаване "_", като ако започват с _, се наричат анонимни
и техните особености ще обсъдим по-късно.
Променливите могат да бъдат остойностени и свободни. Остойностена е променлива, която представя конкретен обект, иначе е свободна.
За да отговори на горния въпрос, Пролог започва да търси отгоре надолу в базата от знания дали има факт, който може да се унифицира с целта. Това означава дали има факт, който има същото име на предикат, както целта, броя на аргументите им съвпадат и съответните им аргументи или съвпадат, ако са обекти, или поне на едното място има променлива. Ако някоя променлива при тази унификация се съпостави на обект, тя се свързва с него. След което Пролог маркира мястото на унификацията, т. е. факт, с който се е унифицирала целта, целта успява т. е. Пролог извежда "yes" и дава обектите, с които са се остойностили променливите. Ако унификация не е възможна дава, отговор "no". Отговорът на горния въпрос е:
X = мери
yes
Ако искаме да видим дали има сведения за други жени, въвеждаме ";" и Пролог започва да търси от маркираното място надолу като при това освобождава всички променливи, които са се стойностили при последната унификация. Това се нарича преудовлетворяване. Отговорът на горния въпрос е "no".
Особености в SP:
- преудовлетворяването в SP става, като се избере
от менюто Run: Next Answer или с F8.
-SP не изписва стойностите на остойностените при
унификация променливи, за да ги видим, трябва да запишем
?- жена (X), write (X), nl.
write и nl са вградени предикати, първият изписва в Output стойността на променливата, а вторият преминава на нов ред, при преудовлетворяване не успяват.
4. Конюнкция. Когато искаме да попитаме едновременно две или повече неща, например: "Харесва ли Джон някоя жена?", това се записва така:
?- харесва (джон, X), жена (X).
T. e. изреждаме предикатите като ги разделяме със ",", която означава "и".
Особености:
- удовлетворяването на целите става в реда, в
който са изброени;
- ако в различните цели участват едни и същи променливи
(не започващи с _), то когато някоя променлива се остойности, то тя става
остойностена и във всички останали цели;
- ако някоя цел не се удовлетвори, то Пролог се
опитва да преудовлетвори най-лявата до нея, като при това се освобождават
само онези променливи, които са се остойностили при съответната унификация.
Ако се опитваме да преудовлетворим цел, която е конюнкция от цели, преудовлетворяването
започва от дясно на ляво по описания по-горе механизъм.
Отговорът на горния въпрос е
X=мери
yes;
no
5. Правила. Ние можем да искаме в базата от знания да задаваме твърдения, които са верни само ако са изпълнени някакви условия. За целта в Пролог се използват правила. Например Джон харесва онези, които харесват вино. На Пролог това изглежда така:
харесва (джон, X) :- харесва (X, вино).
Особености:
- Всяко правило има глава, която в горния пример
е харесва (джон, X), и тяло, в случая
харесва (X, вино), които са разделени
с :-. Тялото на правилото отразява условията, при наличието
на които е вярна главата. Главата на правилото се състои
само от един предикат, а тялото може да е конюнкция от
цели. В правилата, както и във фактите, може да има променливи.
- Променливите, които участват в едно правило,
са локални само за него, т. е. ако имаме друго правило
да речем: Ако някой е крадец и харесва нещо, то той
може да го открадне:
може_да_открадне (X, Y) :- крадец (X), харесва (X, Y).
то X в горното правило не е същото X, както в правилото,
което написахме преди малко;
- при унификацията, ако се унифицират свободна
променлива със свободна променлива, то те се съвместяват
и в последствие ако една от тях се остойности, то
и другата веднага се остойностява със същото нещо;
- когато в базата има правила, търсенето става по същия
начин, като ако целта се унифицира с глава на някое правило,
то тялото се поставя в целта най-отпред в конюнкция с
останалите, ако има такива.
Да разгледаме следната програма:
крадец (джон).
харесва (мери, пица).
харесва (мери, вино).
харесва (джон, X) :- харесва (X, вино).
може_да_открадне (X, Y) :- крадец (X), харесва (X, Y).
?- може_да_открадне (джон, Y).
Отговорът е
Y = мери
yes;
no
Анонимни променливи са тези, които започват с _,
те заместват обекти, които не искаме да kонкретизираме.
За тях не важи правилото, че представят един и същ
обект, т. е. ако имаме
харесва ( _, _), това се унифицира с харесва (джон, мери).
5. Индукция. Понякога е удобно да определяме нещо
индуктивно, т. е. чрез самото себе си. Да речем, искаме да
определим множеството на четните числа по следния начин:
1. 0 е четно.
2. Ако x е четно, то и x+2 e четно.
Да запишем това на Пролог. Нека предполагаме, че имаме предикат плюс на три аргумента, който ако третия му аргумент е свободна променлива, той я остойностява със сумата на първите два, които трябва да са остойностени с числа:
четно(0).
четно(Y) :- четно(X), плюс(X, 2, Y).
Да видим как работи при цел
?- четно(4).
Унифицира се с главата на правилото и започва да
удовлетворява целта четно(X), тя се унифицира с първия факт
и X става нула, но плюс(0, 2, 4) не успява и затова се мъчим
да преудовлетворим четно(X), при това тя се унифицира с
главата на правилото и отново стигаме до удовлетворяване
на целта четно(X), която отново се унифицира с първия
факт, т. е. X става 0, сега вече плюс(0, 2, Y) успява,
Y става 2 отново плюс(2, 2, 4) успява и Пролог отговаря
с yes. Какво би станало, ако бяхме написали програмата:
четно(Y) :- четно(X), плюс(X, 2, Y).
четно(0).
Ще зацикли. Така че когато пишем индуктивни програми, трябва да внимаваме за реда на правилата и фактите, като отчитаме начина, по който търси Пролог.
Задачи:
1. Да разгледаме следната база от знания:
баща (зевс, арес).
майка (хера, арес).
баща (арес, хармония).
родител (X, Y) :- майка (X, Y).
родител (X, Y) :- баща (X, Y).
прародител (X, Y) :- родител (X, Z), родител (Z, Y).
Опишете, като използвате дърво на извод как ще търси Пролог
при задаване на следната цел:
?- родител (X, арес), родител (арес, Z).
2. Да разгледаме база от знания, която определя родословно дърво в термините на мъж, жена, родител. Да се допълни базата, като се определят чрез правила:
- брат:
брат (X, Y) :- родител (Z, X), родител (Z, Y), мъж (X), X \= Y.
Предикатът \= e вграден за Пролог и означава неравно и има инфиксен запис, ако го няма в горното правило, ще получаваме отговори, че някой е брат на себе си.
- баща:
father( X, Y) :-
parentss( X, Y),
male( X).
- сестра:
sister( X, Y) :-
parentss( Z, X),
parentss( Z, Y),
female( X),
X \= Y.
- баба:
grandmother( X, Y) :-
female( X),
parentss( X, Z),
parentss( Z, Y).
- чичо:
uncle( X, Y) :-
brother( X, Z),
parentss( Z, Y).
- братовчед:
cousin( X, Y) :-
uncle( Z, X),
parentss( Z, Y).
cousin( X, Y) :-
parentss( W, X),
sister( Z, W),
parentss( Z, Y).
- баба по майчина линия:
grandmother1( X, Y) :-
parentss( X, Z),
parentss( Z, Y),
female( X),
female(Z).
Задачи за практикума:
1. Да се въведе база от горния вид, с която да се опише
достатъчно подробно (т. е. да има информация за братовчеди,
баби, дядовци, лели чичовци и прочие) нечие родословно
дърво. Чрез трасиране да се разгледа има ли разлика в
отговора и дървото на извод при определянето на баба по
следните два начина:
grandmother( X, Y) :-
female( X),
parentss( X, Z),
parentss( Z, Y).
grandmother( X, Y) :-
parentss( X, Z),
parentss( Z, Y),
female( X).
при задаване на цел
?- grandmother( X, Y).
2. Да се преудовлетвори докато е възможно целта
?- cousin( X, Y). ,
ако базата от знания е достатъчно пълна, ще получите
отговорите по два пъти защо?
3. Определете чрез правило на практикума следните неща
- вуйчо
- дядо
- дядо по бащина линия
- внук
- внучка
- има внуци
- има син
- има наследник от мъжки пол
4. Задайте като цели следните:
- коя е майката на внуците на някой конкретен обект
- коя е майката на момче, чийто баща е някой конкретен
обект.
_____
3. Нека имаме следните предикати за списъци определени чрез факти в базата от знания: empty(X), first(X, U), rest(X, V). Да се дефинират следните правила:
- memb(Z, X)
memb(Z, X):- first(X, Z).
memb(Z, X):- rest(X, V), memb(Z, V).
- sub(X, Y)- всички елементи на X са елементи на Y.
sub(X, Y):-empty(X).
sub(X, Y):-first(X, U), memb(U, Y), rest(X, V), sub(V,
Y).
- нека е даден и предикатът plus, определен както по-горе, да се определи предикат sum(X, U), който е верен, ако Y е сумата от елементите на X.
sum(X, 0):-empty(X).
sum(X, Y):-first(X, U), rest(X, V), sum(V, Z),
plus(U, Z, Y).
4. Като се използват само предикати, да се изрази на Пролог:
- Нито един дракон, който живее в зоопарк, не е щастлив.
нещастен(X):-дракон(X), живее_в_зоопарк(X).
- Всички хора, които посещават зоопарк, са добри.
добър(Х):-човек(Х), посещава_зоопарк(Х).
5. Нека сме определили следната транзитивна релация:
р(а1, а2).
р(а2, а3).
р(а3, а4).
р(а4, а5).
р(А,В):- р(А,С), р(С,В).
Какво ще стане, ако зададем цел р(а5, а4)? Как да изменим програмата така, че да отговаря 'no' в горния случай?
Ще зацикли. Ако я изменим по следния начин, вече няма
да цикли:
р(а1, а2).
р(а2, а3).
р(а3, а4).
р(а4, а5).
т(А,В):- р(А,В).
т(А,В):- р(А,С), т(С,В).
Задачи за практикума
1. Имаме насочен ацикличен граф, зададен чрез факти в смисъла на ребро(А, В). Да се определи предикатът път(А, В), който е верен, ако между А и В има път.
Горното определение от последната задача.
2. Нека имаме определени следните три релации студент(фак.#, име), предмет(пр.#, име), оценка(фак.#, пр.#, оценка). Да се направи база, в която чрез факти да се опишат горните релации. Да се зададат следните вапроси:
-Какво е името на студент, който има 6 по нещо.
?-st(X, Y), oc(X, _, 6), write(Y), nl.
oc1(X,Y,Z):-st(X1,X), pr(Y1,Y),
oc(X1, Y1, Z).
-Какво е името на студент и името на предмет, по
който има 6
?-oc1(X,Y,6), write(X), nl, write(Y), nl.
-Има ли някой 6 по анализ и ТП.
?-oc1(X,analis,6),oc1(X,tp,6), write(X), nl.