Taisyklės Spausdinti
( 4 Votes )
Parašė Aurimas Šimkus   

Vien faktais aprašyti visą programos logiką yra labai sudėtinga. Įsivaizduokite, kad reikia sukurti genialoginį šeimos medį, kad veliau būtų galima patikrinti šeimos ryšius. Jei visa tai bandytume aprašyti vien faktais, tai faktais reikėtų įvardinti tiek tėvus, tiek senelio, tiek prosenelius. Tačiau galima sukurti taisyklių, pagal kurias aprašius vien tėvus bus nustatomi seneliai ir proseneliai - juk senelis yra tėvo tėvas arba mama, o prosenelis yra senelio tėvas arba mama. Taigi be faktų Prolog žinių bazėje taip pat aprašomos ir taisyklės.

Bendroji taisyklės sintaksė:

   antraštė :- sąlygos.

Šitaip užrašyta taisyklė suvokiama taip: jeigu tenkinamos sąlygos, tai antraštė yra gražinama vartotojui. Taisyklės antraštė yra struktūra, kurioje visi argumentai yra kintamieji. Pvz., senelis(X, Y), kur X yra Y senelis. Už antraštės rašomi simboliai :-, suvokiami kaip sąlyga jei. Sąlygos yra viena arba kelios struktūros arba aritmetinės operacijos, aritmetiniai arba termų palyginimai susietos loginiais ryšiais (konjunkcija ir disjunkcija). Struktūros paprastai atitinka anksčiau aprašytų faktų arba taisyklių antraštes, taigi jos čia figūruoja kaip kreipiniai (užklausos į faktus arba taisykles). Nagrinėjamu tevo-senelio atveju taisyklė būtų užrašoma taip:

   senelis(X, Y) :- tevas(X, Z), tevas(Z, Y); tevas(X, Z), mama(X, Z).

        , kur senelis(A, B) suvokiamas (mums nuspręndus) taip: A yra B senelis;
               tevas(A, B) - A yra B tėvas;
               mama(A, B) - A yra B mama.

Prieš tolimesnį pavyzdžio nagrinėjimą reikia trumpai susipažinti su matematine logika. Kaip žinote, Prolog kalboje kablelis reiškia konjunkciją (ir), kabliataškis - disjunkciją (arba). Matematinėje logikoje konjunkcija dar žymima daugybos ženklu *, disjunkcija - sudėties +. Konjunkcija turi aukštenį prioritetą už disjunkciją. Dėl to vienas iš pagrindinių galiojančių dėsnių: A*C+A*B = A*(C+B). 

Aprašytame pavyzdyje matome ir trečiąjį kintamąjį - Z. Tarkime, kad Tomas (Y) yra anūkas seneliui Broniui (X). Juos abu turi sieti Tomo tėvas (Broniaus sūnus) arba Tomo mama. Tiek Tomo tėvą, tiek mamą įsivardinkime Z. Šiuo atveju užtenka vieno kintamojo abiem, nes jie šiuo atveju nėra programiškai susieti. Taigi aprašome dvi sąlygas, norint išsiaiškinti, ar Bronius yra Tomo senelis: (Bronius (X) turi būti Z (Tomo tėvo) tėvas ir Z turi būti Tomo (Y) tėvas) arba (Bronius (X) turi būtį Z (Tomo mamos) tėvas ir Z turi būti Tomo (Y) mama).

Turbūt pastebėjote, kad dėsinėje taisyklės pusėje turime tokią sąlygų konstrukcija: A ir B arba A ir C, kur A, B, C - sąlygos. Iš matematinės logikos žinome, kad šiuo atveju A galime iškelti į priekį prieš skliaustus: A ir (B arba C). Taigi nagrinėjamą taisyklę aprašyti galime šitaip:

   senelis(X, Y) :- tevas(X, Z), (tevas(Z, Y); mama(Z, Y)).

Nagrinėtą šeimos medį galime iliustruoti minimaliu žinių bazės pavyzdžiu:

tevas(bronius, jurgis).
tevas(bronius, rasa).
mama(rasa, tomas).
tevas(jurgis, tomas).
senelis(X, Y) :- tevas(X, Z), (tevas(Z, Y); mama(Z, Y)).

Tada galime pateikti užklausas:

senelis(bronius, tomas).
   - true /*nes bronius yra onos tėvas, kuri yra tomo mama*/
tevas(bronius, Kieno). /*kas yra broniaus vaikai?*/
   - jurgis, ona