Klauzuly v databáze môžu byť trojakého typu:
funktor(arg1, arg2, ... , argN).kde funktor reprezentuje vlastnosť, resp. vzťah a kde argumenty predstavujú jednotlivé objekty, ktorých sa vlastnosť alebo vzťah týka. Každý fakt musí byť ukončený bodkou, za ktorou musí nasledovať aspoň jedna medzera, alebo znak nového riadku. Keď budeme v ďalšom uvádzať príklady štruktúr, budeme ich zapisovať ako fakty (aby pri pokusoch s nimi začiatočníci nezabudli na bodku) ale musíme si byť vedomí toho, že bodka nie je súčasťou štruktúry. Je to dôležité pri použití štruktúry ako zložky nadradenej štruktúry.
dievca(dana). lubi(jana,pivo).Atómy (odpovedajúce približne textovým konštantám procedurálnych jazykov) začínajú v Prolog-u malými písmenami. Považujeme ich za štruktúry s nulovým počtom argumentov.
Argumentami štruktúry môžu byť ľubovoľné objekty jazyka, teda aj štruktúry. To umožňuje vytvárať v zásade ľubovoľne zložité, hierarchicky členené štruktúry.
Je ovšem potrebné si uvedomiť, že predikáty so zhodným menom ale s rozdielnym počtom argumentov sa pokladajú v Prolog-u za odlišné, teda nasledujúce fakty definujú dva rôzne predikáty:
lubi(peter,kovac,pivo). lubi(kovac,pivo).
lubi +--+---+ lubi(peter,pivo(plzenske)). peter pivo | plzenske
yfx - vľavo asociatívny infixný,
Vlastná deklarácia sa robí pomocou štandardného
predikátu
op s vyššie uvedenými tromi argumentami. Deklaráciu operátorov
možno vykonať dvojako:
- v programe sa uvedú príslušné predikáty op
v rámci príkazu, začínajúceho :-
- v priebehu dialógu sa uvedú príslušné predikáty
op po výzve ?- systému ale v každom prípade pred prvým
použitím operátora.
:- op(90,xf,pivo), op(100,xfx,lubi), op(100,xf,je_dievca).Potom nasledujúce dvojice zápisov sú rovnocenné:
je_dievca(dana). dana je_dievca. lubi(jana,vino). jana lubi vino. lubi(peter,pivo(plzenske)). peter lubi plzenske pivo.
?- 3>2. yes ?- 5=4. noZ predošlého dialógu je zrejmé, že systém "pozná" niektoré základné vzťahy z reálneho sveta vo forme zabudovaných predikátov, napr. =, > atď. Pritom komunikácia so systémom prebieha bez akýchkoľvek explicitných príkazov čítania a výpisu.
"Svet" zabudovaných predikátov je ale veľmi obmedzený. Keď používateľ chce riešiť úlohy v zložitejšom "svete", musí uložiť do databázy Prolog-u nové vzťahy, charakterizujúce tento "svet". Príslušné vzťahy sa zadávajú vo forme klauzúl. Do databázy ich môžeme načítať (v prologovskom slangu sa hovorí "nakonzultovať") z nejakého súboru. Predikáty pre čítanie programu zo súboru (medzi vstupno / výstupnými predikátmi).
lubi(peter,mara). lubi(jana,pivo). lubi(dana,vino). lubi(peter,pivo). dievca(dana). dievca(jana). dievca(mara).Úlohou je zistiť, či Mara a Viera sú dievčatá. Odpoveď zistíme v priebehu dialógu (pre objasnenie uvádzame ešte naviac v apostrofoch prepisy otázok používateľa a v úvodzovkách význam odpovedí systému):
?- dievca(mara). 'je Mara dievča ?' yes "áno" ?- dievca(viera). 'je Viera dievča ?' no "nemám informáciu o tom, či Viera je dievča"
?- dievca(D). 'ktoré dievčatá poznáš ?' D = dana ->; "Dana" 'a ešte ?' D = jana ->; "Jana" 'a ešte ?' D = mara ->; "Mara" 'a ešte ?' no "ďalšie dievča nepoznám" ?- lubi(peter,Koho). 'koho ľúbi Peter' Koho = mara ->; "Maru" 'a ešte ?' Koho = pivo ->; "pivo" 'a ešte ?' no "o nikom ďalšom neviem" ?- lubi(Kto,pivo). 'Kto ľúbi pivo ?' Kto = jana ->; "Jana" 'a ešte?' Kto = peter ->; "Peter" 'a ešte ?' no "nepoznám nikoho ďalšieho" ?- lubi(Kto,Koho). 'Kto ľúbi Koho ?' Kto = peter , "Peter ľúbi Koho = mara ->; Maru " 'a ešte ?' Kto = jana , "Jana ľúbi Koho = pivo pivo" 'to stačí' yes "áno, zodpovedal som tvoju otázku"Posledné tri otázky (spolu so štvrtou možnosťou - otázka bez premennej, napr.: lubi(peter, sparty) ) dobre ilustrujú možnosť "viacúčelového" použitia prologovských predikátov. Nie je teda potrebné vopred deklarovať, ktoré argumenty musia byť pri "volaní" predikátu viazané (a už vôbec nie na aký objekt jazyka - nevyžaduje sa teda deklarácia typu) a ktoré musia byť voľné (použijúc terminológiu procedurálnych jazykov: ktoré sú vstupné a ktoré výstupné). Uvedený dialóg je tiež názornou ukážkou generujúcej schopnosti Prolog-u.
Použitím operátorov je možné dosiahnuť ešte prirodzenejšiu formu dialógu.
lubi(peter,pivo(plzenske)). lubi(peter,dievca).a nech sú deklarované operátory (v zhode s príkladom ):
:- op(90,xf,pivo), op(100,xfx,lubi).Úlohou je využiť operátory v dialógu so systémom:
?- peter lubi Co. Co = plzenske pivo -> ; Co = dievcata -> ; no ?- Kto lubi Dobre pivo. Kto = peter, Dobre = plzenske -> ; noPrvá časť dialógu dobre ilustruje skutočnosť, že v štandardnom Prolog-u sú premenné netypované (nie je vopred deklarované na aké objekty sa môže viazať): plzenske pivo je štruktúra, ale dievcata je atóm. Pri zložitejších štruktúrach vyniknú uvedené skutočnosti ešte výraznejšie.
ma_rad(peter, zeny(blond, stihle) ). ma_rad(jozo, zeny(brunet,baculate) ). ma_rad(fero, karban(marias) ). ma_rad(jozo, karban(taroky) ). ma_rad(peter, chlast(pivo(saris,12)) ). ma_rad(fero, chlast(pivo(plzen,10)) ). ma_rad(fero, chlast(rum(tuzemsky)) ).Úlohou je formulovať rôzne otázky týkajúce sa vzťahu ma_rad:
?- ma_rad(Kto, chlast(Alky) ). 'Kto má rád aký alkohol ?' ?- ma_rad(Kto, chlast(_) ). 'Kto rád pije ?' ?- ma_rad(Kto, chlast(pivo(_,12))). 'Kto rád pije dvanástku ?' ?- ma_rad( _ , chlast(pivo(Ake,12))). 'Ake dvanástky poznáš ?' ?- ma_rad(Kto, zeny(_,stihle) ). 'Kto má rád štíhle ženy ?' ?- ma_rad(fero, KohoCo). 'Koho (čo) má Fero rád ?'Použitím anonymnej premennej (podčiarnika) dávame najavo, že na viazaní daných premenných nám nezáleží. Kladenie otázok typu
?- ma_rad(Kto, Nerest(_) ). 'Kto má akú neresť ?'v očakávaní, že dostaneme odpovede Nerest = karban a Nerest = chlast v štandardnom Prolog-u nie je možné. Je však možné dostať sa aj na mená funktorov (príklad na vyhľadanie mien funktorov) a získať tak odpovede uvedeného typu.
?- lubi(peter,pivo), lubi(peter,vino). 'ľúbi Peter aj pivo aj víno ?' no "nie" ?- lubi(peter,pivo); lubi(peter,vino). 'ľúbi Peter pivo alebo víno ?' yes "áno"
hlava :- telo.Hlavu tvorí štruktúra, reprezentujúca nadradený cieľ H (funktor udáva meno predikátu, definovaného týmto pravidlom). Telo je štruktúra, reprezentujúca podmienku T pre splnenie nadradeného cieľa. Telo pravidla niekedy obsahuje iba jeden podcieľ, ale môže ho tvoriť aj zložená podmienka. Čiastkové štruktúry (reprezentujúce príslušné podciele) spojené operátormi konjunkcie (čiarkami - reprezentujú spojku a) a disjunkcie (bodkočiarkami - reprezentujú spojku alebo), pričom je možné použiť aj negáciu (not - pozri kapitolu Negácia podcieľov ). Pravidlo musí byť ukončené bodkou, za ktorou nasleduje znak nového riadku, alebo aspoň jedna medzera.
lubi(peter,D) :- dievca(D), lubi(D,pivo).Premenná D slúži k odovzdávaniu informácií medzi jednotlivými podcieľmi tela pravidla, ako aj medzi telom a hlavou pravidla. Premenná je však lokálna v rámci pravidla - medzi pravidlami nemožno pomocou nej prenášať žiadne informácie.
Nech databáza obsahuje pred uvedeným pravidlom aj nasledujúce fakty:
lubi(peter,pivo). dievca(jana). lubi(jana,pivo).Potom v dialógu
?- lubi(peter,KohoCo). KohoCo = pivo -> ; KohoCo = jana -> ; nozískal systém prvú odpoveď priamo z databázy, ale druhú si musel odvodiť, nakoľko databáza neobsahuje explicitnú informáciu o vzťahu Petra k Jane.
neresti(Kto,Ake) :- ma_rad(Kto,Co), functor(Co,Ake,_).Použitie novonavrhnutého predikátu ilustruje dialóg:
?- neresti(peter,Ake). Ake = zeny -> ; Ake = chlast -> ; no
zuza--+--karol | +-----+-----+ | | | jano--+--jana dana milan-----eva | +---+---+ | | peter anna--+--jozo | vieraZaveďme predikát rodicia s tromi argumentami: Matka, Otec, Dieťa. Tento predikát je možné definovať v súlade so zadaným stromom pomocou nasledujúcich faktov:
rodicia(zuza,karol,jana ). rodicia(zuza,karol,dana ). rodicia(zuza,karol,milan ). rodicia(jana,jano ,peter). rodicia(jana,jano ,anna ). rodicia(anna,jozo ,viera). rodicia(eva ,milan,bezdetni).Bolo potrebné zaviesť špeciálne označenie bezdetni, aby sme mohli pomocou predikátu rodicia reprezentovať aj bezdetné manželské páry.Príklad Pomocou databázy z predošlého príkladu je potrebné zistiť, kto je Petrov dedo. Úlohou je zovšeobecniť vzťah "dedo - vnúča". Petrovho deda zistíme v priebehu dialógu (naša otázka odpovedá výroku dedo je rodičom Petrovej matky, alebo Petrovho otca):
?- rodicia(_,Dedo,Rodic), (rodicia(Rodic,_,peter); rodicia(_,Rodic,peter)). Rodic = jana, Dedo = karol -> ; noPrvá časť otázky znamená Dedo je otec Rodic-a. A súčasne (konjunkcia) s touto prvou požiadavkou má platiť, že Rodic je matka alebo otec "argumentu" peter (druhá časť otázky). Disjunkciu je potrebné uzavrieť do zátvoriek, nakoľko bodkočiarka slabšie viaže operandy ako čiarka predchádzajúcej konjunkcie. Vo svojej odpovedi systém oznámil riešenie, ktoré našiel. Bodkočiarka vyjadruje používateľov pokyn, aby sa systém pokúsil nájsť ďalšie riešenie. Tento pokus bol neúspešný, čo systém oznámil lakonickým no. Podčiarnikmi sme označili v otázke anonymné premenné (premenné, na ktorých "nezáleží", ktoré sa vyskytujú v otázke iba raz).
Vypisovanie podobných dlhých otázok je nepohodlné. Naviac je možné zložitejšie otázky s výhodou hierarchicky členiť na podotázky, ktorým odpovedajú pomocné predikáty. V našom príklade naznačený rozklad vedie na tieto štyri pomocné predikáty:
dedo(Dedo, Vnuca) :- otec(Dedo,R), rodic(R,Vnuca). rodic(Rodic,Dieta) :- otec(Rodic,Dieta) ; matka(Rodic,Dieta). otec(Otec, Dieta) :- rodicia(_,Otec, Dieta), Dieta\= bezdetni. matka(Matka,Dieta) :- rodicia(Matka,_,Dieta), Dieta\=bezdetni.Uvedené pravidlá sú "čitateľnejšie" ako pôvodná otázka a naviac tri prvé - pomocné - pravidlá sa budú hodiť aj pri definovaní ďalších predikátov, charakterizujúcich iné rodinné vzťahy. Aj tu sme použili anonymné premenné všade tam, kde neprenášajú informáciu medzi jednotlivými časťami pravidla. Prvý argument podcieľa rodicia v tele prvého pravidla sme síce mohli označiť premennou Matka, ale táto premenná nikde inde v uvažovanom pravidle nevystupuje a použím anonymnej premennej zdôrazníme, že sme ju úmyselne inde nepoužili, že nám na nej skutočne nezáleží.
Bez testov na konci posledných dvoch pravidiel by systém dával nezmyselné odpovede, napr.:
?- otec(milan,Dieta). Dieta = bezdetni -> 'nechceme hľadať ďalšie riešenia' yesOdpoveď na pôvodnú otázku teraz získame jednoduchšie:
?- dedo(Dedo,peter). Dedo = karol -> 'nechceme hľadať ďalšie riešenia' yes
stryko(Stryko,SynovecNeter) :- brat(Stryko,Rodic), rodic(Rodic,SynovecNeter). brat(Brat,Surodenec) :- surodenci(Brat,Surodenec), muz(Brat). surodenci(Sur1,Sur2) :- rodicia(Matka,Otec,Sur1), rodicia(Matka,Otec,Sur2), Sur1\=Sur2. muz(Otec) :- rodicia(_,Otec,_), Otec \= slob.Aby sme deklarovali, že niekto nemôže byť sám sebe súrodencom, použili sme symbol nerovnosti \=. Predikát muz dáva v niektorých prípadoch chybné výsledky, napr.:
?- muz(peter). noPre odstránenie uvedeného nedostatku je potrebné pôvodnú databázu doplniť o ďalšie fakty, vďaka ktorým aj slobodní chlapci budú považovaní za mužov a slobodné dievčatá za ženy:
rodicia(viera, slob, bezdetni). rodicia(slob, peter, bezdetni). rodicia(dana, slob, bezdetni).Chovanie predikátu muz ostáva však nekorektné pri generovaní alternatív. Napríklad na otázku muz(X) dostaneme trikrát po sebe odpoveď X = karol. Súvisí to s neefektívnou formou reprezentácie rodičovských vzťahov. V príklade na reprezentáciu stromu rodiny v kapitole Rekurzívne údajové štruktúry - zoznamy bude tento nedostatok odstránený.